diff options
Diffstat (limited to 'java/src')
13 files changed, 477 insertions, 51 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java b/java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java new file mode 100644 index 000000000..967cafad0 --- /dev/null +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java @@ -0,0 +1,67 @@ +/* + * 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); + } +} diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java index bbc18f020..d67d9dc4b 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java +++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java @@ -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; @@ -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, event); + onHoverEnterTo(key); } setLastHoverKey(key); } @@ -196,14 +214,14 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> final Key key = getHoverKeyOf(event); if (key != lastKey) { if (lastKey != null) { - onHoverExitKey(lastKey, event); + onHoverExitFrom(lastKey); } if (key != null) { - onHoverEnterKey(key, event); + onHoverEnterTo(key); } } if (key != null) { - onHoverMoveKey(key, event); + onHoverMoveWithin(key); } setLastHoverKey(key); } @@ -215,21 +233,37 @@ 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, event); + 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) { - simulateTouchEvent(MotionEvent.ACTION_DOWN, event); - simulateTouchEvent(MotionEvent.ACTION_UP, event); - onHoverExitKey(key, event); + onRegisterHoverKey(key, event); + onHoverExitFrom(key); } setLastHoverKey(null); } /** + * Register a key that is selected by a hover event + * + * @param key A key to be registered. + * @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); + } + + /** * Simulating a touch event by injecting a synthesized touch event into {@link PointerTracker}. * * @param touchAction The action of the synthesizing touch event. @@ -263,9 +297,11 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * Handles a hover enter event on a key. * * @param key The currently hovered key. - * @param event The hover event that triggers a call to this method. */ - protected void onHoverEnterKey(final Key key, final MotionEvent event) { + protected void onHoverEnterTo(final Key key) { + if (DEBUG_HOVER) { + Log.d(TAG, "onHoverEnterTo: key=" + key); + } key.onPressed(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); @@ -277,17 +313,18 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView> * Handles a hover move event on a key. * * @param key The currently hovered key. - * @param event The hover event that triggers a call to this method. */ - protected void onHoverMoveKey(final Key key, final MotionEvent event) { } + protected void onHoverMoveWithin(final Key key) { } /** * Handles a hover exit event on a key. * * @param key The currently hovered key. - * @param event The hover event that triggers a call to this method. */ - protected void onHoverExitKey(final Key key, final MotionEvent event) { + protected void onHoverExitFrom(final Key key) { + if (DEBUG_HOVER) { + Log.d(TAG, "onHoverExitFrom: key=" + key); + } key.onReleased(); mKeyboardView.invalidateKey(key); final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); diff --git a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java index ec6bb0156..4fdf5b8fa 100644 --- a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java +++ b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java @@ -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(); @@ -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()); } /** @@ -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(); + } } diff --git a/java/src/com/android/inputmethod/accessibility/MoreKeysKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MoreKeysKeyboardAccessibilityDelegate.java new file mode 100644 index 000000000..3a56c5d2a --- /dev/null +++ b/java/src/com/android/inputmethod/accessibility/MoreKeysKeyboardAccessibilityDelegate.java @@ -0,0 +1,114 @@ +/* + * 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.graphics.Rect; +import android.util.Log; +import android.view.MotionEvent; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.MoreKeysKeyboardView; +import com.android.inputmethod.latin.Constants; + +/** + * This class represents a delegate that can be registered in {@link MoreKeysKeyboardView} to + * enhance accessibility support via composition rather via inheritance. + */ +public class MoreKeysKeyboardAccessibilityDelegate + extends KeyboardAccessibilityDelegate<MoreKeysKeyboardView> { + private static final String TAG = MoreKeysKeyboardAccessibilityDelegate.class.getSimpleName(); + + private final Rect mMoreKeysKeyboardValidBounds = new Rect(); + private static final int CLOSING_INSET_IN_PIXEL = 1; + private int mOpenAnnounceResId; + private int mCloseAnnounceResId; + + public MoreKeysKeyboardAccessibilityDelegate(final MoreKeysKeyboardView moreKeysKeyboardView, + final KeyDetector keyDetector) { + super(moreKeysKeyboardView, keyDetector); + } + + public void setOpenAnnounce(final int resId) { + mOpenAnnounceResId = resId; + } + + public void setCloseAnnounce(final int resId) { + mCloseAnnounceResId = resId; + } + + public void onShowMoreKeysKeyboard() { + sendWindowStateChanged(mOpenAnnounceResId); + } + + @Override + protected void onHoverEnter(final MotionEvent event) { + if (DEBUG_HOVER) { + Log.d(TAG, "onHoverEnter: key=" + getHoverKeyOf(event)); + } + super.onHoverEnter(event); + final int actionIndex = event.getActionIndex(); + final int x = (int)event.getX(actionIndex); + final int y = (int)event.getY(actionIndex); + final int pointerId = event.getPointerId(actionIndex); + final long eventTime = event.getEventTime(); + mKeyboardView.onDownEvent(x, y, pointerId, eventTime); + } + + @Override + protected void onHoverMove(final MotionEvent event) { + super.onHoverMove(event); + final int actionIndex = event.getActionIndex(); + final int x = (int)event.getX(actionIndex); + final int y = (int)event.getY(actionIndex); + final int pointerId = event.getPointerId(actionIndex); + final long eventTime = event.getEventTime(); + mKeyboardView.onMoveEvent(x, y, pointerId, eventTime); + } + + @Override + 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) { + super.onHoverExitFrom(lastKey); + } + setLastHoverKey(null); + final int actionIndex = event.getActionIndex(); + final int x = (int)event.getX(actionIndex); + final int y = (int)event.getY(actionIndex); + final int pointerId = event.getPointerId(actionIndex); + final long eventTime = event.getEventTime(); + // A hover exit event at one pixel width or height area on the edges of more keys keyboard + // are treated as closing. + mMoreKeysKeyboardValidBounds.set(0, 0, mKeyboardView.getWidth(), mKeyboardView.getHeight()); + mMoreKeysKeyboardValidBounds.inset(CLOSING_INSET_IN_PIXEL, CLOSING_INSET_IN_PIXEL); + if (mMoreKeysKeyboardValidBounds.contains(x, y)) { + // Invoke {@link MoreKeysKeyboardView#onUpEvent(int,int,int,long)} as if this hover + // exit event selects a key. + mKeyboardView.onUpEvent(x, y, pointerId, eventTime); + mKeyboardView.dismissMoreKeysPanel(); + return; + } + // Close the more keys keyboard. + mKeyboardView.onMoveEvent( + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, pointerId, eventTime); + sendWindowStateChanged(mCloseAnnounceResId); + } +} diff --git a/java/src/com/android/inputmethod/accessibility/MoreSuggestionsAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MoreSuggestionsAccessibilityDelegate.java new file mode 100644 index 000000000..dfc866113 --- /dev/null +++ b/java/src/com/android/inputmethod/accessibility/MoreSuggestionsAccessibilityDelegate.java @@ -0,0 +1,37 @@ +/* + * 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.view.MotionEvent; + +import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.MoreKeysKeyboardView; + +public final class MoreSuggestionsAccessibilityDelegate + extends MoreKeysKeyboardAccessibilityDelegate { + public MoreSuggestionsAccessibilityDelegate(final MoreKeysKeyboardView moreKeysKeyboardView, + final KeyDetector keyDetector) { + super(moreKeysKeyboardView, keyDetector); + } + + @Override + protected void simulateTouchEvent(final int touchAction, final MotionEvent hoverEvent) { + final MotionEvent touchEvent = synthesizeTouchEvent(touchAction, hoverEvent); + mKeyboardView.onTouchEvent(touchEvent); + touchEvent.recycle(); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index 50c82e5f7..4ca4abec6 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -17,12 +17,13 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.content.res.Resources; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import com.android.inputmethod.accessibility.AccessibilityUtils; +import com.android.inputmethod.accessibility.MoreKeysKeyboardAccessibilityDelegate; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.CoordinateUtils; @@ -34,7 +35,7 @@ import com.android.inputmethod.latin.utils.CoordinateUtils; public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel { private final int[] mCoordinates = CoordinateUtils.newInstance(); - protected final KeyDetector mKeyDetector; + protected KeyDetector mKeyDetector; private Controller mController = EMPTY_CONTROLLER; protected KeyboardActionListener mListener; private int mOriginX; @@ -43,6 +44,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel private int mActivePointerId; + protected MoreKeysKeyboardAccessibilityDelegate mAccessibilityDelegate; + public MoreKeysKeyboardView(final Context context, final AttributeSet attrs) { this(context, attrs, R.attr.moreKeysKeyboardViewStyle); } @@ -50,10 +53,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel public MoreKeysKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); - - final Resources res = context.getResources(); - mKeyDetector = new MoreKeysDetector( - res.getDimension(R.dimen.config_more_keys_keyboard_slide_allowance)); + mKeyDetector = new MoreKeysDetector(getResources().getDimension( + R.dimen.config_more_keys_keyboard_slide_allowance)); } @Override @@ -71,8 +72,23 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel @Override public void setKeyboard(final Keyboard keyboard) { super.setKeyboard(keyboard); - mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), - -getPaddingTop() + getVerticalCorrection()); + if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { + // With accessibility mode on, any hover event outside {@link MoreKeysKeyboardView} is + // discarded at {@link InputView#dispatchHoverEvent(MotionEvent)}. Because only a hover + // event that is on this view is dispatched by the platform, we should use a + // {@link KeyDetector} that has no sliding allowance and no hysteresis. + mKeyDetector = new KeyDetector(); + mAccessibilityDelegate = new MoreKeysKeyboardAccessibilityDelegate(this, mKeyDetector); + mAccessibilityDelegate.setOpenAnnounce(R.string.spoken_open_more_keys_keyboard); + mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_keys_keyboard); + mAccessibilityDelegate.setKeyboard(keyboard); + } else { + mKeyDetector = new MoreKeysDetector(getResources().getDimension( + R.dimen.config_more_keys_keyboard_slide_allowance)); + mAccessibilityDelegate = null; + } + mKeyDetector.setKeyboard( + keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection()); } @Override @@ -98,6 +114,10 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel mOriginX = x + container.getPaddingLeft(); mOriginY = y + container.getPaddingTop(); controller.onShowMoreKeysPanel(this); + final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate; + if (accessibilityDelegate != null) { + accessibilityDelegate.onShowMoreKeysKeyboard(); + } } /** @@ -228,6 +248,18 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel return true; } + /** + * {@inheritDoc} + */ + @Override + public boolean onHoverEvent(final MotionEvent event) { + final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate; + if (accessibilityDelegate != null) { + return accessibilityDelegate.onHoverEvent(event); + } + return super.onHoverEvent(event); + } + private View getContainerView() { return (View)getParent(); } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index ff6fd86d0..b6905bc1c 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -1078,6 +1078,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element, mIsTrackingForActionDisabled = true; } + public boolean isInOperation() { + return !mIsTrackingForActionDisabled; + } + + public void cancelLongPressTimer() { + sTimerProxy.cancelLongPressTimerOf(this); + } + public void onLongPressed() { resetKeySelectionByDraggingFinger(); cancelTrackingForAction(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java index 40c915c8d..ab2555802 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java @@ -602,7 +602,7 @@ public final class KeyboardTextsTable { /* keyspec_right_double_angle_quote */ "\u00BB|\u00AB", /* keyspec_left_single_angle_quote */ "\u2039|\u203A", /* keyspec_right_single_angle_quote */ "\u203A|\u2039", - /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\",\'", + /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,\",\'", // U+0651: "ّ" ARABIC SHADDA /* keyhintlabel_period */ "\u0651", /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics", @@ -1551,7 +1551,7 @@ public final class KeyboardTextsTable { /* keyspec_right_double_angle_quote */ "\u00BB|\u00AB", /* keyspec_left_single_angle_quote */ "\u2039|\u203A", /* keyspec_right_single_angle_quote */ "\u203A|\u2039", - /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote", + /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote", // U+064B: "ً" ARABIC FATHATAN /* keyhintlabel_period */ "\u064B", /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics", diff --git a/java/src/com/android/inputmethod/latin/InputView.java b/java/src/com/android/inputmethod/latin/InputView.java index ea7859e60..0801cfa88 100644 --- a/java/src/com/android/inputmethod/latin/InputView.java +++ b/java/src/com/android/inputmethod/latin/InputView.java @@ -23,12 +23,14 @@ import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; +import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.suggestions.MoreSuggestionsView; import com.android.inputmethod.latin.suggestions.SuggestionStripView; public final class InputView extends LinearLayout { private final Rect mInputViewRect = new Rect(); + private MainKeyboardView mMainKeyboardView; private KeyboardTopPaddingForwarder mKeyboardTopPaddingForwarder; private MoreSuggestionsViewCanceler mMoreSuggestionsViewCanceler; private MotionEventForwarder<?, ?> mActiveForwarder; @@ -41,12 +43,11 @@ public final class InputView extends LinearLayout { protected void onFinishInflate() { final SuggestionStripView suggestionStripView = (SuggestionStripView)findViewById(R.id.suggestion_strip_view); - final MainKeyboardView mainKeyboardView = - (MainKeyboardView)findViewById(R.id.keyboard_view); + mMainKeyboardView = (MainKeyboardView)findViewById(R.id.keyboard_view); mKeyboardTopPaddingForwarder = new KeyboardTopPaddingForwarder( - mainKeyboardView, suggestionStripView); + mMainKeyboardView, suggestionStripView); mMoreSuggestionsViewCanceler = new MoreSuggestionsViewCanceler( - mainKeyboardView, suggestionStripView); + mMainKeyboardView, suggestionStripView); } public void setKeyboardTopPadding(final int keyboardTopPadding) { @@ -54,6 +55,17 @@ public final class InputView extends LinearLayout { } @Override + protected boolean dispatchHoverEvent(final MotionEvent event) { + if (AccessibilityUtils.getInstance().isTouchExplorationEnabled() + && mMainKeyboardView.isShowingMoreKeysPanel()) { + // With accessibility mode on, discard hover events while a more keys keyboard is shown. + // The {@link MoreKeysKeyboard} receives hover events directly from the platform. + return true; + } + return super.dispatchHoverEvent(event); + } + + @Override public boolean onInterceptTouchEvent(final MotionEvent me) { final Rect rect = mInputViewRect; getGlobalVisibleRect(rect); diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index f36b42a40..dbbe1a0c5 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -134,7 +134,7 @@ public final class InputLogic { resetComposingState(true /* alsoResetLastComposedWord */); mDeleteCount = 0; mSpaceState = SpaceState.NONE; - mRecapitalizeStatus.deactivate(); + mRecapitalizeStatus.disable(); // Do not perform recapitalize until the cursor is moved once mCurrentlyPressedHardwareKeys.clear(); mSuggestedWords = SuggestedWords.EMPTY; // In some cases (namely, after rotation of the device) editorInfo.initialSelStart is lying @@ -345,10 +345,12 @@ public final class InputLogic { newSelStart, newSelEnd, false /* shouldFinishComposition */); } + // The cursor has been moved : we now accept to perform recapitalization + mRecapitalizeStatus.enable(); // We moved the cursor. If we are touching a word, we need to resume suggestion. mLatinIME.mHandler.postResumeSuggestions(); - // Reset the last recapitalization. - mRecapitalizeStatus.deactivate(); + // Stop the last recapitalization, if started. + mRecapitalizeStatus.stop(); return true; } @@ -369,10 +371,6 @@ public final class InputLogic { final int keyboardShiftMode, // TODO: remove this argument final LatinIME.UIHandler handler) { - // TODO: rework the following to not squash the keycode and the code point into the same - // var because it's confusing. Instead the switch() should handle this in a readable manner. - final int code = - Event.NOT_A_CODE_POINT == event.mCodePoint ? event.mKeyCode : event.mCodePoint; final InputTransaction inputTransaction = new InputTransaction(settingsValues, event, SystemClock.uptimeMillis(), mSpaceState, getActualCapsMode(settingsValues, keyboardShiftMode)); @@ -1138,8 +1136,8 @@ public final class InputLogic { * @param settingsValues The current settings values. */ private void performRecapitalization(final SettingsValues settingsValues) { - if (!mConnection.hasSelection()) { - return; // No selection + if (!mConnection.hasSelection() || !mRecapitalizeStatus.mIsEnabled()) { + return; // No selection or recapitalize is disabled for now } final int selectionStart = mConnection.getExpectedSelectionStart(); final int selectionEnd = mConnection.getExpectedSelectionEnd(); @@ -1149,13 +1147,13 @@ public final class InputLogic { // to suck possibly multiple-megabyte data. return; } - // If we have a recapitalize in progress, use it; otherwise, create a new one. - if (!mRecapitalizeStatus.isActive() + // If we have a recapitalize in progress, use it; otherwise, start a new one. + if (!mRecapitalizeStatus.isStarted() || !mRecapitalizeStatus.isSetAt(selectionStart, selectionEnd)) { final CharSequence selectedText = mConnection.getSelectedText(0 /* flags, 0 for no styles */); if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection - mRecapitalizeStatus.initialize(selectionStart, selectionEnd, selectedText.toString(), + mRecapitalizeStatus.start(selectionStart, selectionEnd, selectedText.toString(), settingsValues.mLocale, settingsValues.mSpacingAndPunctuations.mSortedWordSeparators); // We trim leading and trailing whitespace. @@ -1498,7 +1496,7 @@ public final class InputLogic { } public int getCurrentRecapitalizeState() { - if (!mRecapitalizeStatus.isActive() + if (!mRecapitalizeStatus.isStarted() || !mRecapitalizeStatus.isSetAt(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd())) { // Not recapitalizing at the moment diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java index af46aad96..5eb0377c7 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java @@ -41,6 +41,7 @@ import com.android.inputmethod.keyboard.KeyboardTheme; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; +import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager; import com.android.inputmethod.latin.userdictionary.UserDictionaryList; import com.android.inputmethod.latin.userdictionary.UserDictionarySettings; @@ -212,6 +213,20 @@ public final class SettingsFragment extends InputMethodSettingsFragment textCorrectionGroup.removePreference(dictionaryLink); } + if (ProductionFlag.IS_METRICS_LOGGING_SUPPORTED) { + final Preference enableMetricsLogging = + findPreference(Settings.PREF_ENABLE_METRICS_LOGGING); + if (enableMetricsLogging != null) { + final int applicationLabelRes = context.getApplicationInfo().labelRes; + final String applicationName = res.getString(applicationLabelRes); + final String enableMetricsLoggingTitle = res.getString( + R.string.enable_metrics_logging, applicationName); + enableMetricsLogging.setTitle(enableMetricsLoggingTitle); + } + } else { + removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, textCorrectionGroup); + } + final Preference editPersonalDictionary = findPreference(Settings.PREF_EDIT_PERSONAL_DICTIONARY); final Intent editPersonalDictionaryIntent = editPersonalDictionary.getIntent(); diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index aa59db678..79a735ad6 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -20,6 +20,8 @@ import android.content.Context; import android.util.AttributeSet; import android.util.Log; +import com.android.inputmethod.accessibility.AccessibilityUtils; +import com.android.inputmethod.accessibility.MoreSuggestionsAccessibilityDelegate; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; @@ -50,6 +52,18 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView { } @Override + public void setKeyboard(final Keyboard keyboard) { + super.setKeyboard(keyboard); + // With accessibility mode off, {@link #mAccessibilityDelegate} is set to null at the + // above {@link MoreKeysKeyboardView#setKeyboard(Keyboard)} call. + if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) { + mAccessibilityDelegate = new MoreSuggestionsAccessibilityDelegate(this, mKeyDetector); + mAccessibilityDelegate.setOpenAnnounce(R.string.spoken_open_more_suggestions); + mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_suggestions); + } + } + + @Override protected int getDefaultCoordX() { final MoreSuggestions pane = (MoreSuggestions)getKeyboard(); return pane.mOccupiedWidth / 2; diff --git a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java index 4521ec531..e3cac97f0 100644 --- a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java +++ b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java @@ -62,18 +62,22 @@ public class RecapitalizeStatus { private Locale mLocale; private int[] mSortedSeparators; private String mStringAfter; - private boolean mIsActive; + private boolean mIsStarted; + private boolean mIsEnabled = true; private static final int[] EMPTY_STORTED_SEPARATORS = {}; public RecapitalizeStatus() { // By default, initialize with dummy values that won't match any real recapitalize. - initialize(-1, -1, "", Locale.getDefault(), EMPTY_STORTED_SEPARATORS); - deactivate(); + start(-1, -1, "", Locale.getDefault(), EMPTY_STORTED_SEPARATORS); + stop(); } - public void initialize(final int cursorStart, final int cursorEnd, final String string, + public void start(final int cursorStart, final int cursorEnd, final String string, final Locale locale, final int[] sortedSeparators) { + if (!mIsEnabled) { + return; + } mCursorStartBefore = cursorStart; mStringBefore = string; mCursorStartAfter = cursorStart; @@ -96,15 +100,27 @@ public class RecapitalizeStatus { mRotationStyleCurrentIndex = currentMode; mSkipOriginalMixedCaseMode = true; } - mIsActive = true; + mIsStarted = true; + } + + public void stop() { + mIsStarted = false; + } + + public boolean isStarted() { + return mIsStarted; + } + + public void enable() { + mIsEnabled = true; } - public void deactivate() { - mIsActive = false; + public void disable() { + mIsEnabled = false; } - public boolean isActive() { - return mIsActive; + public boolean mIsEnabled() { + return mIsEnabled; } public boolean isSetAt(final int cursorStart, final int cursorEnd) { |