Loading java/res/values/config-common.xml +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ <integer name="config_max_longpress_timeout">700</integer> <integer name="config_min_longpress_timeout">100</integer> <integer name="config_longpress_timeout_step">10</integer> <integer name="config_accessibility_long_press_key_timeout">1500</integer> <integer name="config_max_more_keys_column">5</integer> <integer name="config_more_keys_keyboard_fadein_anim_time">0</integer> <integer name="config_more_keys_keyboard_fadeout_anim_time">100</integer> Loading java/res/values/strings-talkback-descriptions.xml +5 −0 Original line number Diff line number Diff line Loading @@ -139,4 +139,9 @@ <string name="spoken_symbol_unknown">Unknown symbol</string> <!-- Spoken description for unknown emoji code point. --> <string name="spoken_emoji_unknown">Unknown emoji</string> <!-- Spoken descriptions when opening a more keys keyboard that has alternative characters. --> <string name="spoken_open_more_keys_keyboard">Alternative characters are available</string> <!-- Spoken descriptions when closing a more keys keyboard that has alternative characters. --> <string name="spoken_close_more_keys_keyboard">Alternative characters are dismissed</string> </resources> java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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.content.Context; import android.os.Handler; import android.os.Message; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.R; // Handling long press timer to show a more keys keyboard. final class AccessibilityLongPressTimer extends Handler { public interface LongPressTimerCallback { public void onLongPressed(Key key); } private static final int MSG_LONG_PRESS = 1; private final LongPressTimerCallback mCallback; private final long mConfigAccessibilityLongPressTimeout; public AccessibilityLongPressTimer(final LongPressTimerCallback callback, final Context context) { super(); mCallback = callback; mConfigAccessibilityLongPressTimeout = context.getResources().getInteger( R.integer.config_accessibility_long_press_key_timeout); } @Override public void handleMessage(final Message msg) { switch (msg.what) { case MSG_LONG_PRESS: cancelLongPress(); mCallback.onLongPressed((Key)msg.obj); return; default: super.handleMessage(msg); return; } } public void startLongPress(final Key key) { cancelLongPress(); final Message longPressMessage = obtainMessage(MSG_LONG_PRESS, key); sendMessageDelayed(longPressMessage, mConfigAccessibilityLongPressTimeout); } public void cancelLongPress() { removeMessages(MSG_LONG_PRESS); } } java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java +39 −9 Original line number Diff line number Diff line Loading @@ -33,14 +33,29 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.PointerTracker; /** * This class represents a delegate that can be registered in a class that extends * {@link KeyboardView} to enhance accessibility support via composition rather via inheritance. * * To implement accessibility mode, the target keyboard view has to:<p> * - Call {@link #setKeyboard(Keyboard)} when a new keyboard is set to the keyboard view. * - Dispatch a hover event by calling {@link #onHoverEnter(MotionEvent)}. * * @param <KV> The keyboard view class type. */ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> extends AccessibilityDelegateCompat { private static final String TAG = KeyboardAccessibilityDelegate.class.getSimpleName(); protected static final boolean DEBUG_HOVER = false; protected final KV mKeyboardView; protected final KeyDetector mKeyDetector; private Keyboard mKeyboard; private KeyboardAccessibilityNodeProvider mAccessibilityNodeProvider; private Key mLastHoverKey; public static final int HOVER_EVENT_POINTER_ID = 0; public KeyboardAccessibilityDelegate(final KV keyboardView, final KeyDetector keyDetector) { super(); mKeyboardView = keyboardView; Loading Loading @@ -180,8 +195,11 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> */ protected void onHoverEnter(final MotionEvent event) { final Key key = getHoverKeyOf(event); if (DEBUG_HOVER) { Log.d(TAG, "onHoverEnter: key=" + key); } if (key != null) { onHoverEnterKey(key); onHoverEnterTo(key); } setLastHoverKey(key); } Loading @@ -196,14 +214,14 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> final Key key = getHoverKeyOf(event); if (key != lastKey) { if (lastKey != null) { onHoverExitKey(lastKey); onHoverExitFrom(lastKey); } if (key != null) { onHoverEnterKey(key); onHoverEnterTo(key); } } if (key != null) { onHoverMoveKey(key); onHoverMoveWithin(key); } setLastHoverKey(key); } Loading @@ -215,15 +233,18 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> */ protected void onHoverExit(final MotionEvent event) { final Key lastKey = getLastHoverKey(); if (DEBUG_HOVER) { Log.d(TAG, "onHoverExit: key=" + getHoverKeyOf(event) + " last=" + lastKey); } if (lastKey != null) { onHoverExitKey(lastKey); onHoverExitFrom(lastKey); } final Key key = getHoverKeyOf(event); // Make sure we're not getting an EXIT event because the user slid // off the keyboard area, then force a key press. if (key != null) { onRegisterHoverKey(key, event); onHoverExitKey(key); onHoverExitFrom(key); } setLastHoverKey(null); } Loading @@ -235,6 +256,9 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * @param event A hover exit event that triggers key registering. */ protected void onRegisterHoverKey(final Key key, final MotionEvent event) { if (DEBUG_HOVER) { Log.d(TAG, "onRegisterHoverKey: key=" + key); } simulateTouchEvent(MotionEvent.ACTION_DOWN, event); simulateTouchEvent(MotionEvent.ACTION_UP, event); } Loading Loading @@ -274,7 +298,10 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * * @param key The currently hovered key. */ protected void onHoverEnterKey(final Key key) { protected void onHoverEnterTo(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverEnterTo: key=" + key); } key.onPressed(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); Loading @@ -287,14 +314,17 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * * @param key The currently hovered key. */ protected void onHoverMoveKey(final Key key) { } protected void onHoverMoveWithin(final Key key) { } /** * Handles a hover exit event on a key. * * @param key The currently hovered key. */ protected void onHoverExitKey(final Key key) { protected void onHoverExitFrom(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverExitFrom: key=" + key); } key.onReleased(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); Loading java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java +77 −1 Original line number Diff line number Diff line Loading @@ -17,17 +17,29 @@ package com.android.inputmethod.accessibility; import android.content.Context; import android.os.SystemClock; import android.util.Log; import android.util.SparseIntArray; import android.view.MotionEvent; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; /** * This class represents a delegate that can be registered in {@link MainKeyboardView} to enhance * accessibility support via composition rather via inheritance. */ public final class MainKeyboardAccessibilityDelegate extends KeyboardAccessibilityDelegate<MainKeyboardView> { extends KeyboardAccessibilityDelegate<MainKeyboardView> implements AccessibilityLongPressTimer.LongPressTimerCallback { private static final String TAG = MainKeyboardAccessibilityDelegate.class.getSimpleName(); /** Map of keyboard modes to resource IDs. */ private static final SparseIntArray KEYBOARD_MODE_RES_IDS = new SparseIntArray(); Loading @@ -46,10 +58,15 @@ public final class MainKeyboardAccessibilityDelegate /** The most recently set keyboard mode. */ private int mLastKeyboardMode = KEYBOARD_IS_HIDDEN; private static final int KEYBOARD_IS_HIDDEN = -1; private boolean mShouldIgnoreOnRegisterHoverKey; private final AccessibilityLongPressTimer mAccessibilityLongPressTimer; public MainKeyboardAccessibilityDelegate(final MainKeyboardView mainKeyboardView, final KeyDetector keyDetector) { super(mainKeyboardView, keyDetector); mAccessibilityLongPressTimer = new AccessibilityLongPressTimer( this /* callback */, mainKeyboardView.getContext()); } /** Loading Loading @@ -172,4 +189,63 @@ public final class MainKeyboardAccessibilityDelegate private void announceKeyboardHidden() { sendWindowStateChanged(R.string.announce_keyboard_hidden); } @Override protected void onRegisterHoverKey(final Key key, final MotionEvent event) { if (DEBUG_HOVER) { Log.d(TAG, "onRegisterHoverKey: key=" + key + " ignore=" + mShouldIgnoreOnRegisterHoverKey); } if (!mShouldIgnoreOnRegisterHoverKey) { super.onRegisterHoverKey(key, event); } mShouldIgnoreOnRegisterHoverKey = false; } @Override protected void onHoverEnterTo(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverEnterTo: key=" + key); } mAccessibilityLongPressTimer.cancelLongPress(); super.onHoverEnterTo(key); if (key.isLongPressEnabled()) { mAccessibilityLongPressTimer.startLongPress(key); } } protected void onHoverExitFrom(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverExitFrom: key=" + key); } mAccessibilityLongPressTimer.cancelLongPress(); super.onHoverExitFrom(key); } @Override public void onLongPressed(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onLongPressed: key=" + key); } final PointerTracker tracker = PointerTracker.getPointerTracker(HOVER_EVENT_POINTER_ID); final long eventTime = SystemClock.uptimeMillis(); final int x = key.getHitBox().centerX(); final int y = key.getHitBox().centerY(); final MotionEvent downEvent = MotionEvent.obtain( eventTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0 /* metaState */); // Inject a fake down event to {@link PointerTracker} to handle a long press correctly. tracker.processMotionEvent(downEvent, mKeyDetector); // The above fake down event triggers an unnecessary long press timer that should be // canceled. tracker.cancelLongPressTimer(); downEvent.recycle(); // Invoke {@link MainKeyboardView#onLongPress(PointerTracker)} as if a long press timeout // has passed. mKeyboardView.onLongPress(tracker); // If {@link Key#hasNoPanelAutoMoreKeys()} is true (such as "0 +" key on the phone layout) // or a key invokes IME switcher dialog, we should just ignore the next // {@link #onRegisterHoverKey(Key,MotionEvent)}. It can be determined by whether // {@link PointerTracker} is in operation or not. mShouldIgnoreOnRegisterHoverKey = !tracker.isInOperation(); } } Loading
java/res/values/config-common.xml +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ <integer name="config_max_longpress_timeout">700</integer> <integer name="config_min_longpress_timeout">100</integer> <integer name="config_longpress_timeout_step">10</integer> <integer name="config_accessibility_long_press_key_timeout">1500</integer> <integer name="config_max_more_keys_column">5</integer> <integer name="config_more_keys_keyboard_fadein_anim_time">0</integer> <integer name="config_more_keys_keyboard_fadeout_anim_time">100</integer> Loading
java/res/values/strings-talkback-descriptions.xml +5 −0 Original line number Diff line number Diff line Loading @@ -139,4 +139,9 @@ <string name="spoken_symbol_unknown">Unknown symbol</string> <!-- Spoken description for unknown emoji code point. --> <string name="spoken_emoji_unknown">Unknown emoji</string> <!-- Spoken descriptions when opening a more keys keyboard that has alternative characters. --> <string name="spoken_open_more_keys_keyboard">Alternative characters are available</string> <!-- Spoken descriptions when closing a more keys keyboard that has alternative characters. --> <string name="spoken_close_more_keys_keyboard">Alternative characters are dismissed</string> </resources>
java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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.content.Context; import android.os.Handler; import android.os.Message; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.R; // Handling long press timer to show a more keys keyboard. final class AccessibilityLongPressTimer extends Handler { public interface LongPressTimerCallback { public void onLongPressed(Key key); } private static final int MSG_LONG_PRESS = 1; private final LongPressTimerCallback mCallback; private final long mConfigAccessibilityLongPressTimeout; public AccessibilityLongPressTimer(final LongPressTimerCallback callback, final Context context) { super(); mCallback = callback; mConfigAccessibilityLongPressTimeout = context.getResources().getInteger( R.integer.config_accessibility_long_press_key_timeout); } @Override public void handleMessage(final Message msg) { switch (msg.what) { case MSG_LONG_PRESS: cancelLongPress(); mCallback.onLongPressed((Key)msg.obj); return; default: super.handleMessage(msg); return; } } public void startLongPress(final Key key) { cancelLongPress(); final Message longPressMessage = obtainMessage(MSG_LONG_PRESS, key); sendMessageDelayed(longPressMessage, mConfigAccessibilityLongPressTimeout); } public void cancelLongPress() { removeMessages(MSG_LONG_PRESS); } }
java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java +39 −9 Original line number Diff line number Diff line Loading @@ -33,14 +33,29 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.PointerTracker; /** * This class represents a delegate that can be registered in a class that extends * {@link KeyboardView} to enhance accessibility support via composition rather via inheritance. * * To implement accessibility mode, the target keyboard view has to:<p> * - Call {@link #setKeyboard(Keyboard)} when a new keyboard is set to the keyboard view. * - Dispatch a hover event by calling {@link #onHoverEnter(MotionEvent)}. * * @param <KV> The keyboard view class type. */ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> extends AccessibilityDelegateCompat { private static final String TAG = KeyboardAccessibilityDelegate.class.getSimpleName(); protected static final boolean DEBUG_HOVER = false; protected final KV mKeyboardView; protected final KeyDetector mKeyDetector; private Keyboard mKeyboard; private KeyboardAccessibilityNodeProvider mAccessibilityNodeProvider; private Key mLastHoverKey; public static final int HOVER_EVENT_POINTER_ID = 0; public KeyboardAccessibilityDelegate(final KV keyboardView, final KeyDetector keyDetector) { super(); mKeyboardView = keyboardView; Loading Loading @@ -180,8 +195,11 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> */ protected void onHoverEnter(final MotionEvent event) { final Key key = getHoverKeyOf(event); if (DEBUG_HOVER) { Log.d(TAG, "onHoverEnter: key=" + key); } if (key != null) { onHoverEnterKey(key); onHoverEnterTo(key); } setLastHoverKey(key); } Loading @@ -196,14 +214,14 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> final Key key = getHoverKeyOf(event); if (key != lastKey) { if (lastKey != null) { onHoverExitKey(lastKey); onHoverExitFrom(lastKey); } if (key != null) { onHoverEnterKey(key); onHoverEnterTo(key); } } if (key != null) { onHoverMoveKey(key); onHoverMoveWithin(key); } setLastHoverKey(key); } Loading @@ -215,15 +233,18 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> */ protected void onHoverExit(final MotionEvent event) { final Key lastKey = getLastHoverKey(); if (DEBUG_HOVER) { Log.d(TAG, "onHoverExit: key=" + getHoverKeyOf(event) + " last=" + lastKey); } if (lastKey != null) { onHoverExitKey(lastKey); onHoverExitFrom(lastKey); } final Key key = getHoverKeyOf(event); // Make sure we're not getting an EXIT event because the user slid // off the keyboard area, then force a key press. if (key != null) { onRegisterHoverKey(key, event); onHoverExitKey(key); onHoverExitFrom(key); } setLastHoverKey(null); } Loading @@ -235,6 +256,9 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * @param event A hover exit event that triggers key registering. */ protected void onRegisterHoverKey(final Key key, final MotionEvent event) { if (DEBUG_HOVER) { Log.d(TAG, "onRegisterHoverKey: key=" + key); } simulateTouchEvent(MotionEvent.ACTION_DOWN, event); simulateTouchEvent(MotionEvent.ACTION_UP, event); } Loading Loading @@ -274,7 +298,10 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * * @param key The currently hovered key. */ protected void onHoverEnterKey(final Key key) { protected void onHoverEnterTo(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverEnterTo: key=" + key); } key.onPressed(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); Loading @@ -287,14 +314,17 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * * @param key The currently hovered key. */ protected void onHoverMoveKey(final Key key) { } protected void onHoverMoveWithin(final Key key) { } /** * Handles a hover exit event on a key. * * @param key The currently hovered key. */ protected void onHoverExitKey(final Key key) { protected void onHoverExitFrom(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverExitFrom: key=" + key); } key.onReleased(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); Loading
java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java +77 −1 Original line number Diff line number Diff line Loading @@ -17,17 +17,29 @@ package com.android.inputmethod.accessibility; import android.content.Context; import android.os.SystemClock; import android.util.Log; import android.util.SparseIntArray; import android.view.MotionEvent; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; /** * This class represents a delegate that can be registered in {@link MainKeyboardView} to enhance * accessibility support via composition rather via inheritance. */ public final class MainKeyboardAccessibilityDelegate extends KeyboardAccessibilityDelegate<MainKeyboardView> { extends KeyboardAccessibilityDelegate<MainKeyboardView> implements AccessibilityLongPressTimer.LongPressTimerCallback { private static final String TAG = MainKeyboardAccessibilityDelegate.class.getSimpleName(); /** Map of keyboard modes to resource IDs. */ private static final SparseIntArray KEYBOARD_MODE_RES_IDS = new SparseIntArray(); Loading @@ -46,10 +58,15 @@ public final class MainKeyboardAccessibilityDelegate /** The most recently set keyboard mode. */ private int mLastKeyboardMode = KEYBOARD_IS_HIDDEN; private static final int KEYBOARD_IS_HIDDEN = -1; private boolean mShouldIgnoreOnRegisterHoverKey; private final AccessibilityLongPressTimer mAccessibilityLongPressTimer; public MainKeyboardAccessibilityDelegate(final MainKeyboardView mainKeyboardView, final KeyDetector keyDetector) { super(mainKeyboardView, keyDetector); mAccessibilityLongPressTimer = new AccessibilityLongPressTimer( this /* callback */, mainKeyboardView.getContext()); } /** Loading Loading @@ -172,4 +189,63 @@ public final class MainKeyboardAccessibilityDelegate private void announceKeyboardHidden() { sendWindowStateChanged(R.string.announce_keyboard_hidden); } @Override protected void onRegisterHoverKey(final Key key, final MotionEvent event) { if (DEBUG_HOVER) { Log.d(TAG, "onRegisterHoverKey: key=" + key + " ignore=" + mShouldIgnoreOnRegisterHoverKey); } if (!mShouldIgnoreOnRegisterHoverKey) { super.onRegisterHoverKey(key, event); } mShouldIgnoreOnRegisterHoverKey = false; } @Override protected void onHoverEnterTo(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverEnterTo: key=" + key); } mAccessibilityLongPressTimer.cancelLongPress(); super.onHoverEnterTo(key); if (key.isLongPressEnabled()) { mAccessibilityLongPressTimer.startLongPress(key); } } protected void onHoverExitFrom(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onHoverExitFrom: key=" + key); } mAccessibilityLongPressTimer.cancelLongPress(); super.onHoverExitFrom(key); } @Override public void onLongPressed(final Key key) { if (DEBUG_HOVER) { Log.d(TAG, "onLongPressed: key=" + key); } final PointerTracker tracker = PointerTracker.getPointerTracker(HOVER_EVENT_POINTER_ID); final long eventTime = SystemClock.uptimeMillis(); final int x = key.getHitBox().centerX(); final int y = key.getHitBox().centerY(); final MotionEvent downEvent = MotionEvent.obtain( eventTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0 /* metaState */); // Inject a fake down event to {@link PointerTracker} to handle a long press correctly. tracker.processMotionEvent(downEvent, mKeyDetector); // The above fake down event triggers an unnecessary long press timer that should be // canceled. tracker.cancelLongPressTimer(); downEvent.recycle(); // Invoke {@link MainKeyboardView#onLongPress(PointerTracker)} as if a long press timeout // has passed. mKeyboardView.onLongPress(tracker); // If {@link Key#hasNoPanelAutoMoreKeys()} is true (such as "0 +" key on the phone layout) // or a key invokes IME switcher dialog, we should just ignore the next // {@link #onRegisterHoverKey(Key,MotionEvent)}. It can be determined by whether // {@link PointerTracker} is in operation or not. mShouldIgnoreOnRegisterHoverKey = !tracker.isInOperation(); } }