Loading java/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ LOCAL_REQUIRED_MODULES := libjni_latinime LOCAL_STATIC_JAVA_LIBRARIES := android-common LOCAL_STATIC_JAVA_LIBRARIES += inputmethod-common LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 # Do not compress dictionary files to mmap dict data runtime LOCAL_AAPT_FLAGS := -0 .dict Loading java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java 0 → 100644 +377 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 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.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.support.v4.view.ViewCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat; import android.support.v4.view.accessibility.AccessibilityRecordCompat; import android.util.Log; import android.util.SparseArray; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.accessibility.AccessibilityEvent; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardView; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * Exposes a virtual view sub-tree for {@link KeyboardView} and generates * {@link AccessibilityEvent}s for individual {@link Key}s. * <p> * A virtual sub-tree is composed of imaginary {@link View}s that are reported * as a part of the view hierarchy for accessibility purposes. This enables * custom views that draw complex content to report them selves as a tree of * virtual views, thus conveying their logical structure. * </p> */ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat { private static final String TAG = AccessibilityEntityProvider.class.getSimpleName(); private final KeyboardView mKeyboardView; private final InputMethodService mInputMethodService; private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper; private final AccessibilityUtils mAccessibilityUtils; /** A map of integer IDs to {@link Key}s. */ private final SparseArray<Key> mVirtualViewIdToKey = new SparseArray<Key>(); /** Temporary rect used to calculate in-screen bounds. */ private final Rect mTempBoundsInScreen = new Rect(); /** The parent view's cached on-screen location. */ private final int[] mParentLocation = new int[2]; public AccessibilityEntityProvider(KeyboardView keyboardView, InputMethodService inputMethod) { mKeyboardView = keyboardView; mInputMethodService = inputMethod; mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance(); mAccessibilityUtils = AccessibilityUtils.getInstance(); assignVirtualViewIds(); updateParentLocation(); // Ensure that the on-screen bounds are cleared when the layout changes. mKeyboardView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener); } /** * Creates and populates an {@link AccessibilityEvent} for the specified key * and event type. * * @param key A key on the host keyboard view. * @param eventType The event type to create. * @return A populated {@link AccessibilityEvent} for the key. * @see AccessibilityEvent */ public AccessibilityEvent createAccessibilityEvent(Key key, 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.getText().add(keyDescription); final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event); record.setSource(mKeyboardView, virtualViewId); return event; } /** * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or * the host View itself if <code>virtualViewId</code> equals to {@link View#NO_ID}. * <p> * A virtual descendant is an imaginary View that is reported as a part of * the view hierarchy for accessibility purposes. This enables custom views * that draw complex content to report them selves as a tree of virtual * views, thus conveying their logical structure. * </p> * <p> * The implementer is responsible for obtaining an accessibility node info * from the pool of reusable instances and setting the desired properties of * the node info before returning it. * </p> * * @param virtualViewId A client defined virtual view id. * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual * descendant or the host View. * @see AccessibilityNodeInfoCompat */ @Override public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) { AccessibilityNodeInfoCompat info = null; 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); // Add the virtual children of the root View. // TODO(alanv): Need to assign a unique ID to each key. final Keyboard keyboard = mKeyboardView.getKeyboard(); final Set<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.addAction(AccessibilityNodeInfoCompat.ACTION_SELECT); info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION); info.setPackageName(mKeyboardView.getContext().getPackageName()); info.setClassName(key.getClass().getName()); info.setBoundsInParent(boundsInParent); info.setBoundsInScreen(boundsInScreen); info.setParent(mKeyboardView); info.setSource(mKeyboardView, virtualViewId); info.setBoundsInScreen(boundsInScreen); info.setText(keyDescription); } return info; } /** * Performs an accessibility action on a virtual view, i.e. a descendant of * the host View, with the given <code>virtualViewId</code> or the host View itself if * <code>virtualViewId</code> equals to {@link View#NO_ID}. * * @param action The action to perform. * @param virtualViewId A client defined virtual view id. * @return True if the action was performed. * @see #createAccessibilityNodeInfo(int) * @see AccessibilityNodeInfoCompat */ @Override public boolean performAccessibilityAction(int action, int virtualViewId) { if (virtualViewId == View.NO_ID) { // Perform the action on the host View. switch (action) { case AccessibilityNodeInfoCompat.ACTION_SELECT: if (!mKeyboardView.isSelected()) { mKeyboardView.setSelected(true); return mKeyboardView.isSelected(); } break; case AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION: if (mKeyboardView.isSelected()) { mKeyboardView.setSelected(false); return !mKeyboardView.isSelected(); } break; } } else { // Find the view that corresponds to the given id. final Key child = mVirtualViewIdToKey.get(virtualViewId); if (child == null) return false; // Perform the action on a virtual view. switch (action) { case AccessibilityNodeInfoCompat.ACTION_SELECT: // TODO: Provide some focus indicator. return true; case AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION: // TODO: Provide some clear focus indicator. return true; } } return false; } /** * Finds {@link AccessibilityNodeInfoCompat}s by text. The match is case * insensitive containment. The search is relative to the virtual view, i.e. * a descendant of the host View, with the given <code>virtualViewId</code> or the host * View itself <code>virtualViewId</code> equals to {@link View#NO_ID}. * * @param virtualViewId A client defined virtual view id which defined the * root of the tree in which to perform the search. * @param text The searched text. * @return A list of node info. * @see #createAccessibilityNodeInfo(int) * @see AccessibilityNodeInfoCompat */ @Override public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText( String text, int virtualViewId) { final String searchedLowerCase = text.toLowerCase(); final Keyboard keyboard = mKeyboardView.getKeyboard(); List<AccessibilityNodeInfoCompat> results = null; if (virtualViewId == View.NO_ID) { for (Key key : keyboard.mKeys) { results = findByTextAndPopulate(searchedLowerCase, key, results); } } else { final Key key = mVirtualViewIdToKey.get(virtualViewId); results = findByTextAndPopulate(searchedLowerCase, key, results); } if (results == null) { return Collections.emptyList(); } return results; } /** * Helper method for {@link #findAccessibilityNodeInfosByText(String, int)}. * Takes a current set of results and matches a specified key against a * lower-case search string. Returns an updated list of results. * * @param searchedLowerCase The lower-case search string. * @param key The key to compare against. * @param results The current list of results, or {@code null} if no results * found. * @return An updated list of results, or {@code null} if no results found. */ private List<AccessibilityNodeInfoCompat> findByTextAndPopulate(String searchedLowerCase, Key key, List<AccessibilityNodeInfoCompat> results) { if (!keyContainsText(key, searchedLowerCase)) { return results; } final int childVirtualViewId = generateVirtualViewIdForKey(key); final AccessibilityNodeInfoCompat nodeInfo = createAccessibilityNodeInfo( childVirtualViewId); if (results == null) { results = new LinkedList<AccessibilityNodeInfoCompat>(); } results.add(nodeInfo); return results; } /** * Returns whether a key's current description contains the lower-case * search text. * * @param key The key to compare against. * @param textLowerCase The lower-case search string. * @return {@code true} if the key contains the search text. */ private boolean keyContainsText(Key key, String textLowerCase) { if (key == null) { return false; } final String description = getKeyDescription(key); if (description == null) { return false; } return description.toLowerCase().contains(textLowerCase); } /** * Returns the context-specific description for a {@link Key}. * * @param key The key to describe. * @return The context-specific description of the key. */ private String getKeyDescription(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; } /** * 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(); final Set<Key> keySet = keyboard.mKeys; for (Key key : keySet) { final int virtualViewId = generateVirtualViewIdForKey(key); mVirtualViewIdToKey.put(virtualViewId, key); } } /** * Updates the parent's on-screen location. */ private void updateParentLocation() { mKeyboardView.getLocationOnScreen(mParentLocation); } /** * Generates a virtual view identifier for the specified key. * * @param key The key to identify. * @return A virtual view identifier. */ private static int generateVirtualViewIdForKey(Key key) { // The key code is unique within an instance of a Keyboard. return key.mCode; } private final OnGlobalLayoutListener mGlobalLayoutListener = new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { assignVirtualViewIds(); updateParentLocation(); } }; } java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java +5 −6 Original line number Diff line number Diff line Loading @@ -21,13 +21,14 @@ import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.os.SystemClock; import android.provider.Settings; import android.support.v4.view.MotionEventCompat; import android.util.Log; import android.view.MotionEvent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.AccessibilityManagerCompatWrapper; import com.android.inputmethod.compat.AccessibilityManagerCompatUtils; import com.android.inputmethod.compat.AudioManagerCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.MotionEventCompatUtils; Loading @@ -44,7 +45,6 @@ public class AccessibilityUtils { private Context mContext; private AccessibilityManager mAccessibilityManager; private AccessibilityManagerCompatWrapper mCompatManager; private AudioManagerCompatWrapper mAudioManager; /* Loading Loading @@ -77,7 +77,6 @@ public class AccessibilityUtils { mContext = context; mAccessibilityManager = (AccessibilityManager) context .getSystemService(Context.ACCESSIBILITY_SERVICE); mCompatManager = new AccessibilityManagerCompatWrapper(mAccessibilityManager); final AudioManager audioManager = (AudioManager) context .getSystemService(Context.AUDIO_SERVICE); Loading @@ -94,7 +93,7 @@ public class AccessibilityUtils { public boolean isTouchExplorationEnabled() { return ENABLE_ACCESSIBILITY && mAccessibilityManager.isEnabled() && mCompatManager.isTouchExplorationEnabled(); && AccessibilityManagerCompatUtils.isTouchExplorationEnabled(mAccessibilityManager); } /** Loading @@ -110,7 +109,7 @@ public class AccessibilityUtils { return action == MotionEventCompatUtils.ACTION_HOVER_ENTER || action == MotionEventCompatUtils.ACTION_HOVER_EXIT || action == MotionEventCompatUtils.ACTION_HOVER_MOVE; || action == MotionEventCompat.ACTION_HOVER_MOVE; } /** Loading java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +108 −56 File changed.Preview size limit exceeded, changes collapsed. Show changes java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java +3 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.inputmethod.accessibility; import android.content.Context; import android.os.Message; import android.support.v4.view.MotionEventCompat; import android.view.MotionEvent; import android.view.ViewConfiguration; Loading @@ -32,7 +33,7 @@ import com.android.inputmethod.latin.StaticInnerHandlerWrapper; * properties: * <ul> * <li>Begins with a {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * <li>Contains any number of {@link MotionEventCompatUtils#ACTION_HOVER_MOVE} * <li>Contains any number of {@link MotionEventCompat#ACTION_HOVER_MOVE} * events * <li>Ends with a {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * <li>Maximum duration of 250 milliseconds Loading Loading @@ -128,7 +129,7 @@ public abstract class FlickGestureDetector { final float distanceSquare = calculateDistanceSquare(mCachedHoverEnter, event); switch (event.getAction()) { case MotionEventCompatUtils.ACTION_HOVER_MOVE: case MotionEventCompat.ACTION_HOVER_MOVE: // Consume all valid move events before timeout. return true; case MotionEventCompatUtils.ACTION_HOVER_EXIT: Loading Loading
java/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ LOCAL_REQUIRED_MODULES := libjni_latinime LOCAL_STATIC_JAVA_LIBRARIES := android-common LOCAL_STATIC_JAVA_LIBRARIES += inputmethod-common LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 # Do not compress dictionary files to mmap dict data runtime LOCAL_AAPT_FLAGS := -0 .dict Loading
java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java 0 → 100644 +377 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 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.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.support.v4.view.ViewCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat; import android.support.v4.view.accessibility.AccessibilityRecordCompat; import android.util.Log; import android.util.SparseArray; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.accessibility.AccessibilityEvent; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardView; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * Exposes a virtual view sub-tree for {@link KeyboardView} and generates * {@link AccessibilityEvent}s for individual {@link Key}s. * <p> * A virtual sub-tree is composed of imaginary {@link View}s that are reported * as a part of the view hierarchy for accessibility purposes. This enables * custom views that draw complex content to report them selves as a tree of * virtual views, thus conveying their logical structure. * </p> */ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat { private static final String TAG = AccessibilityEntityProvider.class.getSimpleName(); private final KeyboardView mKeyboardView; private final InputMethodService mInputMethodService; private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper; private final AccessibilityUtils mAccessibilityUtils; /** A map of integer IDs to {@link Key}s. */ private final SparseArray<Key> mVirtualViewIdToKey = new SparseArray<Key>(); /** Temporary rect used to calculate in-screen bounds. */ private final Rect mTempBoundsInScreen = new Rect(); /** The parent view's cached on-screen location. */ private final int[] mParentLocation = new int[2]; public AccessibilityEntityProvider(KeyboardView keyboardView, InputMethodService inputMethod) { mKeyboardView = keyboardView; mInputMethodService = inputMethod; mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance(); mAccessibilityUtils = AccessibilityUtils.getInstance(); assignVirtualViewIds(); updateParentLocation(); // Ensure that the on-screen bounds are cleared when the layout changes. mKeyboardView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener); } /** * Creates and populates an {@link AccessibilityEvent} for the specified key * and event type. * * @param key A key on the host keyboard view. * @param eventType The event type to create. * @return A populated {@link AccessibilityEvent} for the key. * @see AccessibilityEvent */ public AccessibilityEvent createAccessibilityEvent(Key key, 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.getText().add(keyDescription); final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event); record.setSource(mKeyboardView, virtualViewId); return event; } /** * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or * the host View itself if <code>virtualViewId</code> equals to {@link View#NO_ID}. * <p> * A virtual descendant is an imaginary View that is reported as a part of * the view hierarchy for accessibility purposes. This enables custom views * that draw complex content to report them selves as a tree of virtual * views, thus conveying their logical structure. * </p> * <p> * The implementer is responsible for obtaining an accessibility node info * from the pool of reusable instances and setting the desired properties of * the node info before returning it. * </p> * * @param virtualViewId A client defined virtual view id. * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual * descendant or the host View. * @see AccessibilityNodeInfoCompat */ @Override public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) { AccessibilityNodeInfoCompat info = null; 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); // Add the virtual children of the root View. // TODO(alanv): Need to assign a unique ID to each key. final Keyboard keyboard = mKeyboardView.getKeyboard(); final Set<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.addAction(AccessibilityNodeInfoCompat.ACTION_SELECT); info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION); info.setPackageName(mKeyboardView.getContext().getPackageName()); info.setClassName(key.getClass().getName()); info.setBoundsInParent(boundsInParent); info.setBoundsInScreen(boundsInScreen); info.setParent(mKeyboardView); info.setSource(mKeyboardView, virtualViewId); info.setBoundsInScreen(boundsInScreen); info.setText(keyDescription); } return info; } /** * Performs an accessibility action on a virtual view, i.e. a descendant of * the host View, with the given <code>virtualViewId</code> or the host View itself if * <code>virtualViewId</code> equals to {@link View#NO_ID}. * * @param action The action to perform. * @param virtualViewId A client defined virtual view id. * @return True if the action was performed. * @see #createAccessibilityNodeInfo(int) * @see AccessibilityNodeInfoCompat */ @Override public boolean performAccessibilityAction(int action, int virtualViewId) { if (virtualViewId == View.NO_ID) { // Perform the action on the host View. switch (action) { case AccessibilityNodeInfoCompat.ACTION_SELECT: if (!mKeyboardView.isSelected()) { mKeyboardView.setSelected(true); return mKeyboardView.isSelected(); } break; case AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION: if (mKeyboardView.isSelected()) { mKeyboardView.setSelected(false); return !mKeyboardView.isSelected(); } break; } } else { // Find the view that corresponds to the given id. final Key child = mVirtualViewIdToKey.get(virtualViewId); if (child == null) return false; // Perform the action on a virtual view. switch (action) { case AccessibilityNodeInfoCompat.ACTION_SELECT: // TODO: Provide some focus indicator. return true; case AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION: // TODO: Provide some clear focus indicator. return true; } } return false; } /** * Finds {@link AccessibilityNodeInfoCompat}s by text. The match is case * insensitive containment. The search is relative to the virtual view, i.e. * a descendant of the host View, with the given <code>virtualViewId</code> or the host * View itself <code>virtualViewId</code> equals to {@link View#NO_ID}. * * @param virtualViewId A client defined virtual view id which defined the * root of the tree in which to perform the search. * @param text The searched text. * @return A list of node info. * @see #createAccessibilityNodeInfo(int) * @see AccessibilityNodeInfoCompat */ @Override public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText( String text, int virtualViewId) { final String searchedLowerCase = text.toLowerCase(); final Keyboard keyboard = mKeyboardView.getKeyboard(); List<AccessibilityNodeInfoCompat> results = null; if (virtualViewId == View.NO_ID) { for (Key key : keyboard.mKeys) { results = findByTextAndPopulate(searchedLowerCase, key, results); } } else { final Key key = mVirtualViewIdToKey.get(virtualViewId); results = findByTextAndPopulate(searchedLowerCase, key, results); } if (results == null) { return Collections.emptyList(); } return results; } /** * Helper method for {@link #findAccessibilityNodeInfosByText(String, int)}. * Takes a current set of results and matches a specified key against a * lower-case search string. Returns an updated list of results. * * @param searchedLowerCase The lower-case search string. * @param key The key to compare against. * @param results The current list of results, or {@code null} if no results * found. * @return An updated list of results, or {@code null} if no results found. */ private List<AccessibilityNodeInfoCompat> findByTextAndPopulate(String searchedLowerCase, Key key, List<AccessibilityNodeInfoCompat> results) { if (!keyContainsText(key, searchedLowerCase)) { return results; } final int childVirtualViewId = generateVirtualViewIdForKey(key); final AccessibilityNodeInfoCompat nodeInfo = createAccessibilityNodeInfo( childVirtualViewId); if (results == null) { results = new LinkedList<AccessibilityNodeInfoCompat>(); } results.add(nodeInfo); return results; } /** * Returns whether a key's current description contains the lower-case * search text. * * @param key The key to compare against. * @param textLowerCase The lower-case search string. * @return {@code true} if the key contains the search text. */ private boolean keyContainsText(Key key, String textLowerCase) { if (key == null) { return false; } final String description = getKeyDescription(key); if (description == null) { return false; } return description.toLowerCase().contains(textLowerCase); } /** * Returns the context-specific description for a {@link Key}. * * @param key The key to describe. * @return The context-specific description of the key. */ private String getKeyDescription(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; } /** * 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(); final Set<Key> keySet = keyboard.mKeys; for (Key key : keySet) { final int virtualViewId = generateVirtualViewIdForKey(key); mVirtualViewIdToKey.put(virtualViewId, key); } } /** * Updates the parent's on-screen location. */ private void updateParentLocation() { mKeyboardView.getLocationOnScreen(mParentLocation); } /** * Generates a virtual view identifier for the specified key. * * @param key The key to identify. * @return A virtual view identifier. */ private static int generateVirtualViewIdForKey(Key key) { // The key code is unique within an instance of a Keyboard. return key.mCode; } private final OnGlobalLayoutListener mGlobalLayoutListener = new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { assignVirtualViewIds(); updateParentLocation(); } }; }
java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java +5 −6 Original line number Diff line number Diff line Loading @@ -21,13 +21,14 @@ import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.os.SystemClock; import android.provider.Settings; import android.support.v4.view.MotionEventCompat; import android.util.Log; import android.view.MotionEvent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.AccessibilityManagerCompatWrapper; import com.android.inputmethod.compat.AccessibilityManagerCompatUtils; import com.android.inputmethod.compat.AudioManagerCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.MotionEventCompatUtils; Loading @@ -44,7 +45,6 @@ public class AccessibilityUtils { private Context mContext; private AccessibilityManager mAccessibilityManager; private AccessibilityManagerCompatWrapper mCompatManager; private AudioManagerCompatWrapper mAudioManager; /* Loading Loading @@ -77,7 +77,6 @@ public class AccessibilityUtils { mContext = context; mAccessibilityManager = (AccessibilityManager) context .getSystemService(Context.ACCESSIBILITY_SERVICE); mCompatManager = new AccessibilityManagerCompatWrapper(mAccessibilityManager); final AudioManager audioManager = (AudioManager) context .getSystemService(Context.AUDIO_SERVICE); Loading @@ -94,7 +93,7 @@ public class AccessibilityUtils { public boolean isTouchExplorationEnabled() { return ENABLE_ACCESSIBILITY && mAccessibilityManager.isEnabled() && mCompatManager.isTouchExplorationEnabled(); && AccessibilityManagerCompatUtils.isTouchExplorationEnabled(mAccessibilityManager); } /** Loading @@ -110,7 +109,7 @@ public class AccessibilityUtils { return action == MotionEventCompatUtils.ACTION_HOVER_ENTER || action == MotionEventCompatUtils.ACTION_HOVER_EXIT || action == MotionEventCompatUtils.ACTION_HOVER_MOVE; || action == MotionEventCompat.ACTION_HOVER_MOVE; } /** Loading
java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +108 −56 File changed.Preview size limit exceeded, changes collapsed. Show changes
java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java +3 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.inputmethod.accessibility; import android.content.Context; import android.os.Message; import android.support.v4.view.MotionEventCompat; import android.view.MotionEvent; import android.view.ViewConfiguration; Loading @@ -32,7 +33,7 @@ import com.android.inputmethod.latin.StaticInnerHandlerWrapper; * properties: * <ul> * <li>Begins with a {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * <li>Contains any number of {@link MotionEventCompatUtils#ACTION_HOVER_MOVE} * <li>Contains any number of {@link MotionEventCompat#ACTION_HOVER_MOVE} * events * <li>Ends with a {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * <li>Maximum duration of 250 milliseconds Loading Loading @@ -128,7 +129,7 @@ public abstract class FlickGestureDetector { final float distanceSquare = calculateDistanceSquare(mCachedHoverEnter, event); switch (event.getAction()) { case MotionEventCompatUtils.ACTION_HOVER_MOVE: case MotionEventCompat.ACTION_HOVER_MOVE: // Consume all valid move events before timeout. return true; case MotionEventCompatUtils.ACTION_HOVER_EXIT: Loading