aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java133
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java129
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java37
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java201
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java226
-rw-r--r--java/src/com/android/inputmethod/compat/AccessibilityEventCompatUtils.java39
-rw-r--r--java/src/com/android/inputmethod/compat/AccessibilityManagerCompatWrapper.java42
-rw-r--r--java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java23
-rw-r--r--java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java35
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java19
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java66
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboard.java13
-rw-r--r--java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java7
-rw-r--r--java/src/com/android/inputmethod/keyboard/PopupPanel.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/Key.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java35
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java33
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java2
19 files changed, 953 insertions, 98 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
new file mode 100644
index 000000000..ae614b7e0
--- /dev/null
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.inputmethodservice.InputMethodService;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.inputmethod.compat.AccessibilityEventCompatUtils;
+import com.android.inputmethod.compat.AccessibilityManagerCompatWrapper;
+import com.android.inputmethod.compat.MotionEventCompatUtils;
+
+public class AccessibilityUtils {
+ private static final String TAG = AccessibilityUtils.class.getSimpleName();
+ private static final String CLASS = AccessibilityUtils.class.getClass().getName();
+ private static final String PACKAGE = AccessibilityUtils.class.getClass().getPackage()
+ .getName();
+
+ private static final AccessibilityUtils sInstance = new AccessibilityUtils();
+
+ private AccessibilityManager mAccessibilityManager;
+ private AccessibilityManagerCompatWrapper mCompatManager;
+
+ /*
+ * Setting this constant to {@code false} will disable all keyboard
+ * accessibility code, regardless of whether Accessibility is turned on in
+ * the system settings. It should ONLY be used in the event of an emergency.
+ */
+ private static final boolean ENABLE_ACCESSIBILITY = true;
+
+ public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
+ if (!ENABLE_ACCESSIBILITY)
+ return;
+
+ // These only need to be initialized if the kill switch is off.
+ sInstance.initInternal(inputMethod, prefs);
+ KeyCodeDescriptionMapper.init(inputMethod, prefs);
+ AccessibleInputMethodServiceProxy.init(inputMethod, prefs);
+ AccessibleKeyboardViewProxy.init(inputMethod, prefs);
+ }
+
+ public static AccessibilityUtils getInstance() {
+ return sInstance;
+ }
+
+ private AccessibilityUtils() {
+ // This class is not publicly instantiable.
+ }
+
+ private void initInternal(Context context, SharedPreferences prefs) {
+ mAccessibilityManager = (AccessibilityManager) context
+ .getSystemService(Context.ACCESSIBILITY_SERVICE);
+ mCompatManager = new AccessibilityManagerCompatWrapper(mAccessibilityManager);
+ }
+
+ /**
+ * Returns {@code true} if touch exploration is enabled. Currently, this
+ * means that the kill switch is off, the device supports touch exploration,
+ * and a spoken feedback service is turned on.
+ *
+ * @return {@code true} if touch exploration is enabled.
+ */
+ public boolean isTouchExplorationEnabled() {
+ return ENABLE_ACCESSIBILITY
+ && AccessibilityEventCompatUtils.supportsTouchExploration()
+ && mAccessibilityManager.isEnabled()
+ && !mCompatManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
+ }
+
+ /**
+ * Returns {@true} if the provided event is a touch exploration (e.g. hover)
+ * event. This is used to determine whether the event should be processed by
+ * the touch exploration code within the keyboard.
+ *
+ * @param event The event to check.
+ * @return {@true} is the event is a touch exploration event
+ */
+ public boolean isTouchExplorationEvent(MotionEvent event) {
+ final int action = event.getAction();
+
+ return action == MotionEventCompatUtils.ACTION_HOVER_ENTER
+ || action == MotionEventCompatUtils.ACTION_HOVER_EXIT
+ || action == MotionEventCompatUtils.ACTION_HOVER_MOVE;
+ }
+
+ /**
+ * Sends the specified text to the {@link AccessibilityManager} to be
+ * spoken.
+ *
+ * @param text the text to speak
+ */
+ public void speak(CharSequence text) {
+ if (!mAccessibilityManager.isEnabled()) {
+ Log.e(TAG, "Attempted to speak when accessibility was disabled!");
+ return;
+ }
+
+ // The following is a hack to avoid using the heavy-weight TextToSpeech
+ // class. Instead, we're just forcing a fake AccessibilityEvent into
+ // the screen reader to make it speak.
+ final AccessibilityEvent event = AccessibilityEvent
+ .obtain(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER);
+
+ event.setPackageName(PACKAGE);
+ event.setClassName(CLASS);
+ event.setEventTime(SystemClock.uptimeMillis());
+ event.setEnabled(true);
+ event.getText().add(text);
+
+ mAccessibilityManager.sendAccessibilityEvent(event);
+ }
+}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
new file mode 100644
index 000000000..043266c70
--- /dev/null
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.SharedPreferences;
+import android.inputmethodservice.InputMethodService;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+
+import com.android.inputmethod.latin.R;
+
+public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActionListener {
+ private static final AccessibleInputMethodServiceProxy sInstance =
+ new AccessibleInputMethodServiceProxy();
+
+ /*
+ * Delay for the handler event that's fired when Accessibility is on and the
+ * user hovers outside of any valid keys. This is used to let the user know
+ * that if they lift their finger, nothing will be typed.
+ */
+ private static final long DELAY_NO_HOVER_SELECTION = 250;
+
+ private InputMethodService mInputMethod;
+
+ private AccessibilityHandler mAccessibilityHandler;
+
+ private class AccessibilityHandler extends Handler {
+ private static final int MSG_NO_HOVER_SELECTION = 0;
+
+ public AccessibilityHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_NO_HOVER_SELECTION:
+ notifyNoHoverSelection();
+ break;
+ }
+ }
+
+ public void postNoHoverSelection() {
+ removeMessages(MSG_NO_HOVER_SELECTION);
+ sendEmptyMessageDelayed(MSG_NO_HOVER_SELECTION, DELAY_NO_HOVER_SELECTION);
+ }
+
+ public void cancelNoHoverSelection() {
+ removeMessages(MSG_NO_HOVER_SELECTION);
+ }
+ }
+
+ public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
+ sInstance.initInternal(inputMethod, prefs);
+ }
+
+ public static AccessibleInputMethodServiceProxy getInstance() {
+ return sInstance;
+ }
+
+ private AccessibleInputMethodServiceProxy() {
+ // Not publicly instantiable.
+ }
+
+ private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) {
+ mInputMethod = inputMethod;
+ mAccessibilityHandler = new AccessibilityHandler(inputMethod.getMainLooper());
+ }
+
+ /**
+ * If touch exploration is enabled, cancels the event sent by
+ * {@link AccessibleInputMethodServiceProxy#onHoverExit(int)} because the
+ * user is currently hovering above a key.
+ */
+ @Override
+ public void onHoverEnter(int primaryCode) {
+ mAccessibilityHandler.cancelNoHoverSelection();
+ }
+
+ /**
+ * If touch exploration is enabled, sends a delayed event to notify the user
+ * that they are not currently hovering above a key.
+ */
+ @Override
+ public void onHoverExit(int primaryCode) {
+ mAccessibilityHandler.postNoHoverSelection();
+ }
+
+ /**
+ * When Accessibility is turned on, notifies the user that they are not
+ * currently hovering above a key. By default this will speak the currently
+ * entered text.
+ */
+ private void notifyNoHoverSelection() {
+ final ExtractedText extracted = mInputMethod.getCurrentInputConnection().getExtractedText(
+ new ExtractedTextRequest(), 0);
+
+ if (extracted == null)
+ return;
+
+ final CharSequence text;
+
+ if (TextUtils.isEmpty(extracted.text)) {
+ text = mInputMethod.getString(R.string.spoken_no_text_entered);
+ } else {
+ text = mInputMethod.getString(R.string.spoken_current_text_is, extracted.text);
+ }
+
+ AccessibilityUtils.getInstance().speak(text);
+ }
+}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java
new file mode 100644
index 000000000..12c59d0fc
--- /dev/null
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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;
+
+public interface AccessibleKeyboardActionListener {
+ /**
+ * Called when the user hovers inside a key. This is sent only when
+ * Accessibility is turned on. For keys that repeat, this is only called
+ * once.
+ *
+ * @param primaryCode the code of the key that was hovered over
+ */
+ public void onHoverEnter(int primaryCode);
+
+ /**
+ * Called when the user hovers outside a key. This is sent only when
+ * Accessibility is turned on. For keys that repeat, this is only called
+ * once.
+ *
+ * @param primaryCode the code of the key that was hovered over
+ */
+ public void onHoverExit(int primaryCode);
+}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
new file mode 100644
index 000000000..1adef9057
--- /dev/null
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * 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.content.SharedPreferences;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.inputmethod.compat.AccessibilityEventCompatUtils;
+import com.android.inputmethod.compat.MotionEventCompatUtils;
+import com.android.inputmethod.keyboard.KeyDetector;
+import com.android.inputmethod.keyboard.KeyboardView;
+import com.android.inputmethod.keyboard.PointerTracker;
+import com.android.inputmethod.keyboard.internal.Key;
+
+public class AccessibleKeyboardViewProxy {
+ private static final String TAG = AccessibleKeyboardViewProxy.class.getSimpleName();
+ private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy();
+
+ // Delay in milliseconds between key press DOWN and UP events
+ private static final long DELAY_KEY_PRESS = 10;
+
+ private int mScaledEdgeSlop;
+ private KeyboardView mView;
+ private AccessibleKeyboardActionListener mListener;
+
+ private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY;
+ private int mLastX = -1;
+ private int mLastY = -1;
+
+ public static void init(Context context, SharedPreferences prefs) {
+ sInstance.initInternal(context, prefs);
+ sInstance.mListener = AccessibleInputMethodServiceProxy.getInstance();
+ }
+
+ public static AccessibleKeyboardViewProxy getInstance() {
+ return sInstance;
+ }
+
+ public static void setView(KeyboardView view) {
+ sInstance.mView = view;
+ }
+
+ private AccessibleKeyboardViewProxy() {
+ // Not publicly instantiable.
+ }
+
+ private void initInternal(Context context, SharedPreferences prefs) {
+ final Paint paint = new Paint();
+ paint.setTextAlign(Paint.Align.LEFT);
+ paint.setTextSize(14.0f);
+ paint.setAntiAlias(true);
+ paint.setColor(Color.YELLOW);
+
+ mScaledEdgeSlop = ViewConfiguration.get(context).getScaledEdgeSlop();
+ }
+
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event,
+ PointerTracker tracker) {
+ if (mView == null) {
+ Log.e(TAG, "No keyboard view set!");
+ return false;
+ }
+
+ switch (event.getEventType()) {
+ case AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER:
+ final Key key = tracker.getKey(mLastHoverKeyIndex);
+
+ if (key == null)
+ break;
+
+ final CharSequence description = KeyCodeDescriptionMapper.getInstance()
+ .getDescriptionForKey(mView.getContext(), mView.getKeyboard(), key);
+
+ if (description == null)
+ return false;
+
+ event.getText().add(description);
+
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Receives hover events when accessibility is turned on in API > 11. In
+ * earlier API levels, events are manually routed from onTouchEvent.
+ *
+ * @param event The hover event.
+ * @return {@code true} if the event is handled
+ */
+ public boolean onHoverEvent(MotionEvent event, PointerTracker tracker) {
+ return onTouchExplorationEvent(event, tracker);
+ }
+
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ // Since touch exploration translates hover double-tap to a regular
+ // single-tap, we're going to drop non-touch exploration events.
+ if (!AccessibilityUtils.getInstance().isTouchExplorationEvent(event))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Handles touch exploration events when Accessibility is turned on.
+ *
+ * @param event The touch exploration hover event.
+ * @return {@code true} if the event was handled
+ */
+ private boolean onTouchExplorationEvent(MotionEvent event, PointerTracker tracker) {
+ final int x = (int) event.getX();
+ final int y = (int) event.getY();
+
+ switch (event.getAction()) {
+ case MotionEventCompatUtils.ACTION_HOVER_ENTER:
+ case MotionEventCompatUtils.ACTION_HOVER_MOVE:
+ final int keyIndex = tracker.getKeyIndexOn(x, y);
+
+ if (keyIndex != mLastHoverKeyIndex) {
+ fireKeyHoverEvent(tracker, mLastHoverKeyIndex, false);
+ mLastHoverKeyIndex = keyIndex;
+ mLastX = x;
+ mLastY = y;
+ fireKeyHoverEvent(tracker, mLastHoverKeyIndex, true);
+ }
+
+ return true;
+ case MotionEventCompatUtils.ACTION_HOVER_EXIT:
+ final int width = mView.getWidth();
+ final int height = mView.getHeight();
+
+ if (x < mScaledEdgeSlop || y < mScaledEdgeSlop || x >= (width - mScaledEdgeSlop)
+ || y >= (height - mScaledEdgeSlop)) {
+ fireKeyHoverEvent(tracker, mLastHoverKeyIndex, false);
+ mLastHoverKeyIndex = KeyDetector.NOT_A_KEY;
+ mLastX = -1;
+ mLastY = -1;
+ } else if (mLastHoverKeyIndex != KeyDetector.NOT_A_KEY) {
+ fireKeyPressEvent(tracker, mLastX, mLastY, event.getEventTime());
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private void fireKeyHoverEvent(PointerTracker tracker, int keyIndex, boolean entering) {
+ if (mListener == null) {
+ Log.e(TAG, "No accessible keyboard action listener set!");
+ return;
+ }
+
+ if (mView == null) {
+ Log.e(TAG, "No keyboard view set!");
+ return;
+ }
+
+ if (keyIndex == KeyDetector.NOT_A_KEY)
+ return;
+
+ final Key key = tracker.getKey(keyIndex);
+
+ if (key == null)
+ return;
+
+ if (entering) {
+ mListener.onHoverEnter(key.mCode);
+ mView.sendAccessibilityEvent(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER);
+ } else {
+ mListener.onHoverExit(key.mCode);
+ mView.sendAccessibilityEvent(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_EXIT);
+ }
+ }
+
+ private void fireKeyPressEvent(PointerTracker tracker, int x, int y, long eventTime) {
+ tracker.onDownEvent(x, y, eventTime, null);
+ tracker.onUpEvent(x, y, eventTime + DELAY_KEY_PRESS, null);
+ }
+}
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
new file mode 100644
index 000000000..5e6f10b04
--- /dev/null
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.content.SharedPreferences;
+import android.text.TextUtils;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.internal.Key;
+import com.android.inputmethod.latin.R;
+
+import java.util.HashMap;
+
+public class KeyCodeDescriptionMapper {
+ private static KeyCodeDescriptionMapper sInstance = new KeyCodeDescriptionMapper();
+
+ // Map of key labels to spoken description resource IDs
+ private final HashMap<CharSequence, Integer> mKeyLabelMap;
+
+ // Map of key codes to spoken description resource IDs
+ private final HashMap<Integer, Integer> mKeyCodeMap;
+
+ // Map of shifted key codes to spoken description resource IDs
+ private final HashMap<Integer, Integer> mShiftedKeyCodeMap;
+
+ // Map of shift-locked key codes to spoken description resource IDs
+ private final HashMap<Integer, Integer> mShiftLockedKeyCodeMap;
+
+ public static void init(Context context, SharedPreferences prefs) {
+ sInstance.initInternal(context, prefs);
+ }
+
+ public static KeyCodeDescriptionMapper getInstance() {
+ return sInstance;
+ }
+
+ private KeyCodeDescriptionMapper() {
+ mKeyLabelMap = new HashMap<CharSequence, Integer>();
+ mKeyCodeMap = new HashMap<Integer, Integer>();
+ mShiftedKeyCodeMap = new HashMap<Integer, Integer>();
+ mShiftLockedKeyCodeMap = new HashMap<Integer, Integer>();
+ }
+
+ private void initInternal(Context context, SharedPreferences prefs) {
+ // Manual label substitutions for key labels with no string resource
+ mKeyLabelMap.put(":-)", R.string.spoken_description_smiley);
+
+ // Symbols that most TTS engines can't speak
+ mKeyCodeMap.put((int) '.', R.string.spoken_description_period);
+ mKeyCodeMap.put((int) ',', R.string.spoken_description_comma);
+ mKeyCodeMap.put((int) '(', R.string.spoken_description_left_parenthesis);
+ mKeyCodeMap.put((int) ')', R.string.spoken_description_right_parenthesis);
+ mKeyCodeMap.put((int) ':', R.string.spoken_description_colon);
+ mKeyCodeMap.put((int) ';', R.string.spoken_description_semicolon);
+ mKeyCodeMap.put((int) '!', R.string.spoken_description_exclamation_mark);
+ mKeyCodeMap.put((int) '?', R.string.spoken_description_question_mark);
+ mKeyCodeMap.put((int) '\"', R.string.spoken_description_double_quote);
+ mKeyCodeMap.put((int) '\'', R.string.spoken_description_single_quote);
+ mKeyCodeMap.put((int) '*', R.string.spoken_description_star);
+ mKeyCodeMap.put((int) '#', R.string.spoken_description_pound);
+ mKeyCodeMap.put((int) ' ', R.string.spoken_description_space);
+
+ // Non-ASCII symbols (must use escape codes!)
+ mKeyCodeMap.put((int) '\u2022', R.string.spoken_description_dot);
+ mKeyCodeMap.put((int) '\u221A', R.string.spoken_description_square_root);
+ mKeyCodeMap.put((int) '\u03C0', R.string.spoken_description_pi);
+ mKeyCodeMap.put((int) '\u0394', R.string.spoken_description_delta);
+ mKeyCodeMap.put((int) '\u2122', R.string.spoken_description_trademark);
+ mKeyCodeMap.put((int) '\u2105', R.string.spoken_description_care_of);
+ mKeyCodeMap.put((int) '\u2026', R.string.spoken_description_ellipsis);
+ mKeyCodeMap.put((int) '\u201E', R.string.spoken_description_low_double_quote);
+
+ // Special non-character codes defined in Keyboard
+ mKeyCodeMap.put(Keyboard.CODE_DELETE, R.string.spoken_description_delete);
+ mKeyCodeMap.put(Keyboard.CODE_ENTER, R.string.spoken_description_return);
+ mKeyCodeMap.put(Keyboard.CODE_SETTINGS, R.string.spoken_description_settings);
+ mKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_shift);
+ mKeyCodeMap.put(Keyboard.CODE_SHORTCUT, R.string.spoken_description_mic);
+ mKeyCodeMap.put(Keyboard.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol);
+ mKeyCodeMap.put(Keyboard.CODE_TAB, R.string.spoken_description_tab);
+
+ // Shifted versions of non-character codes defined in Keyboard
+ mShiftedKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_shift_shifted);
+
+ // Shift-locked versions of non-character codes defined in Keyboard
+ mShiftLockedKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_caps_lock);
+ }
+
+ /**
+ * Returns the localized description of the action performed by a specified
+ * key based on the current keyboard state.
+ * <p>
+ * The order of precedence for key descriptions is:
+ * <ol>
+ * <li>Manually-defined based on the key label</li>
+ * <li>Automatic or manually-defined based on the key code</li>
+ * <li>Automatically based on the key label</li>
+ * <li>{code null} for keys with no label or key code defined</li>
+ * </p>
+ *
+ * @param context The package's context.
+ * @param keyboard The keyboard on which the key resides.
+ * @param key The key from which to obtain a description.
+ * @return a character sequence describing the action performed by pressing
+ * the key
+ */
+ public CharSequence getDescriptionForKey(Context context, Keyboard keyboard, Key key) {
+ if (key.mCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ final CharSequence description = getDescriptionForSwitchAlphaSymbol(context, keyboard);
+ if (description != null)
+ return description;
+ }
+
+ if (!TextUtils.isEmpty(key.mLabel)) {
+ final String label = key.mLabel.toString().trim();
+
+ if (mKeyLabelMap.containsKey(label)) {
+ return context.getString(mKeyLabelMap.get(label));
+ } else if (label.length() == 1
+ || (keyboard.isManualTemporaryUpperCase() && !TextUtils
+ .isEmpty(key.mHintLetter))) {
+ return getDescriptionForKeyCode(context, keyboard, key);
+ } else {
+ return label;
+ }
+ } else if (key.mCode != Keyboard.CODE_DUMMY) {
+ return getDescriptionForKeyCode(context, keyboard, key);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a context-specific description for the CODE_SWITCH_ALPHA_SYMBOL
+ * key or {@code null} if there is not a description provided for the
+ * current keyboard context.
+ *
+ * @param context The package's context.
+ * @param keyboard The keyboard on which the key resides.
+ * @return a character sequence describing the action performed by pressing
+ * the key
+ */
+ private CharSequence getDescriptionForSwitchAlphaSymbol(Context context, Keyboard keyboard) {
+ final KeyboardId id = keyboard.mId;
+
+ if (id.isAlphabetKeyboard()) {
+ return context.getString(R.string.spoken_description_to_symbol);
+ } else if (id.isSymbolsKeyboard()) {
+ return context.getString(R.string.spoken_description_to_alpha);
+ } else if (id.isPhoneSymbolsKeyboard()) {
+ return context.getString(R.string.spoken_description_to_numeric);
+ } else if (id.isPhoneKeyboard()) {
+ return context.getString(R.string.spoken_description_to_symbol);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the keycode for the specified key given the current keyboard
+ * state.
+ *
+ * @param keyboard The keyboard on which the key resides.
+ * @param key The key from which to obtain a key code.
+ * @return the key code for the specified key
+ */
+ private int getCorrectKeyCode(Keyboard keyboard, Key key) {
+ if (keyboard.isManualTemporaryUpperCase() && !TextUtils.isEmpty(key.mHintLetter)) {
+ return key.mHintLetter.charAt(0);
+ } else {
+ return key.mCode;
+ }
+ }
+
+ /**
+ * Returns a localized character sequence describing what will happen when
+ * the specified key is pressed based on its key code.
+ * <p>
+ * The order of precedence for key code descriptions is:
+ * <ol>
+ * <li>Manually-defined shift-locked description</li>
+ * <li>Manually-defined shifted description</li>
+ * <li>Manually-defined normal description</li>
+ * <li>Automatic based on the character represented by the key code</li>
+ * <li>Fall-back for undefined or control characters</li>
+ * </ol>
+ * </p>
+ *
+ * @param context The package's context.
+ * @param keyboard The keyboard on which the key resides.
+ * @param key The key from which to obtain a description.
+ * @return a character sequence describing the action performed by pressing
+ * the key
+ */
+ private CharSequence getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key) {
+ final int code = getCorrectKeyCode(keyboard, key);
+
+ if (keyboard.isShiftLocked() && mShiftLockedKeyCodeMap.containsKey(code)) {
+ return context.getString(mShiftLockedKeyCodeMap.get(code));
+ } else if (keyboard.isShiftedOrShiftLocked() && mShiftedKeyCodeMap.containsKey(code)) {
+ return context.getString(mShiftedKeyCodeMap.get(code));
+ } else if (mKeyCodeMap.containsKey(code)) {
+ return context.getString(mKeyCodeMap.get(code));
+ } else if (Character.isDefined(code) && !Character.isISOControl(code)) {
+ return Character.toString((char) code);
+ } else {
+ return context.getString(R.string.spoken_description_unknown, code);
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/AccessibilityEventCompatUtils.java b/java/src/com/android/inputmethod/compat/AccessibilityEventCompatUtils.java
new file mode 100644
index 000000000..50057727a
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/AccessibilityEventCompatUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.compat;
+
+import android.view.accessibility.AccessibilityEvent;
+
+import java.lang.reflect.Field;
+
+public class AccessibilityEventCompatUtils {
+ public static final int TYPE_VIEW_HOVER_ENTER = 0x80;
+ public static final int TYPE_VIEW_HOVER_EXIT = 0x100;
+
+ private static final Field FIELD_TYPE_VIEW_HOVER_ENTER = CompatUtils.getField(
+ AccessibilityEvent.class, "TYPE_VIEW_HOVER_ENTER");
+ private static final Field FIELD_TYPE_VIEW_HOVER_EXIT = CompatUtils.getField(
+ AccessibilityEvent.class, "TYPE_VIEW_HOVER_EXIT");
+ private static final Integer OBJ_TYPE_VIEW_HOVER_ENTER = (Integer) CompatUtils
+ .getFieldValue(null, null, FIELD_TYPE_VIEW_HOVER_ENTER);
+ private static final Integer OBJ_TYPE_VIEW_HOVER_EXIT = (Integer) CompatUtils
+ .getFieldValue(null, null, FIELD_TYPE_VIEW_HOVER_EXIT);
+
+ public static boolean supportsTouchExploration() {
+ return OBJ_TYPE_VIEW_HOVER_ENTER != null && OBJ_TYPE_VIEW_HOVER_EXIT != null;
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/AccessibilityManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/AccessibilityManagerCompatWrapper.java
new file mode 100644
index 000000000..4db1c7a24
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/AccessibilityManagerCompatWrapper.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.compat;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.view.accessibility.AccessibilityManager;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+public class AccessibilityManagerCompatWrapper {
+ private static final Method METHOD_getEnabledAccessibilityServiceList = CompatUtils.getMethod(
+ AccessibilityManager.class, "getEnabledAccessibilityServiceList", int.class);
+
+ private final AccessibilityManager mManager;
+
+ public AccessibilityManagerCompatWrapper(AccessibilityManager manager) {
+ mManager = manager;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) {
+ return (List<AccessibilityServiceInfo>) CompatUtils.invoke(mManager,
+ Collections.<AccessibilityServiceInfo>emptyList(),
+ METHOD_getEnabledAccessibilityServiceList, feedbackType);
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java b/java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java
new file mode 100644
index 000000000..8518a4a78
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.compat;
+
+public class MotionEventCompatUtils {
+ public static final int ACTION_HOVER_MOVE = 0x7;
+ public static final int ACTION_HOVER_ENTER = 0x9;
+ public static final int ACTION_HOVER_EXIT = 0xA;
+}
diff --git a/java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java b/java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java
index 2dba01432..b718ebbb7 100644
--- a/java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java
@@ -129,7 +129,7 @@ public class VoiceInput implements OnClickListener {
private int mAfterVoiceInputSelectionSpan = 0;
private int mState = DEFAULT;
-
+
private final static int MSG_RESET = 1;
private final Handler mHandler = new Handler() {
@@ -192,7 +192,7 @@ public class VoiceInput implements OnClickListener {
}
mBlacklist = new Whitelist();
- mBlacklist.addApp("com.android.setupwizard");
+ mBlacklist.addApp("com.google.android.setupwizard");
}
public void setCursorPos(int pos) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index d97bb6730..b91134dd6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -42,7 +42,6 @@ public class KeyboardId {
public final int mWidth;
public final int mMode;
public final int mXmlId;
- public final int mColorScheme;
public final boolean mNavigateAction;
public final boolean mPasswordInput;
public final boolean mHasSettingsKey;
@@ -56,9 +55,9 @@ public class KeyboardId {
private final int mHashCode;
- public KeyboardId(String xmlName, int xmlId, int colorScheme, Locale locale, int orientation,
- int width, int mode, EditorInfo attribute, boolean hasSettingsKey,
- boolean voiceKeyEnabled, boolean hasVoiceKey, boolean enableShiftLock) {
+ public KeyboardId(String xmlName, int xmlId, Locale locale, int orientation, int width,
+ int mode, EditorInfo attribute, boolean hasSettingsKey, boolean voiceKeyEnabled,
+ boolean hasVoiceKey, boolean enableShiftLock) {
final int inputType = (attribute != null) ? attribute.inputType : 0;
final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
this.mLocale = locale;
@@ -66,7 +65,6 @@ public class KeyboardId {
this.mWidth = width;
this.mMode = mode;
this.mXmlId = xmlId;
- this.mColorScheme = colorScheme;
// Note: Turn off checking navigation flag to show TAB key for now.
this.mNavigateAction = InputTypeCompatUtils.isWebInputType(inputType);
// || EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
@@ -91,7 +89,6 @@ public class KeyboardId {
width,
mode,
xmlId,
- colorScheme,
mNavigateAction,
mPasswordInput,
hasSettingsKey,
@@ -103,15 +100,15 @@ public class KeyboardId {
}
public KeyboardId cloneWithNewLayout(String xmlName, int xmlId) {
- return new KeyboardId(xmlName, xmlId, mColorScheme, mLocale, mOrientation, mWidth, mMode,
- mAttribute, mHasSettingsKey, mVoiceKeyEnabled, mHasVoiceKey, mEnableShiftLock);
+ return new KeyboardId(xmlName, xmlId, mLocale, mOrientation, mWidth, mMode, mAttribute,
+ mHasSettingsKey, mVoiceKeyEnabled, mHasVoiceKey, mEnableShiftLock);
}
public KeyboardId cloneWithNewGeometry(int width) {
if (mWidth == width)
return this;
- return new KeyboardId(mXmlName, mXmlId, mColorScheme, mLocale, mOrientation, width, mMode,
- mAttribute, mHasSettingsKey, mVoiceKeyEnabled, mHasVoiceKey, mEnableShiftLock);
+ return new KeyboardId(mXmlName, mXmlId, mLocale, mOrientation, width, mMode, mAttribute,
+ mHasSettingsKey, mVoiceKeyEnabled, mHasVoiceKey, mEnableShiftLock);
}
public int getXmlId() {
@@ -123,13 +120,17 @@ public class KeyboardId {
}
public boolean isSymbolsKeyboard() {
- return mXmlId == R.xml.kbd_symbols;
+ return mXmlId == R.xml.kbd_symbols || mXmlId == R.xml.kbd_symbols_shift;
}
public boolean isPhoneKeyboard() {
return mMode == MODE_PHONE;
}
+ public boolean isPhoneSymbolsKeyboard() {
+ return mXmlId == R.xml.kbd_phone_symbols;
+ }
+
public boolean isNumberKeyboard() {
return mMode == MODE_NUMBER;
}
@@ -145,7 +146,6 @@ public class KeyboardId {
&& other.mWidth == this.mWidth
&& other.mMode == this.mMode
&& other.mXmlId == this.mXmlId
- && other.mColorScheme == this.mColorScheme
&& other.mNavigateAction == this.mNavigateAction
&& other.mPasswordInput == this.mPasswordInput
&& other.mHasSettingsKey == this.mHasSettingsKey
@@ -162,13 +162,12 @@ public class KeyboardId {
@Override
public String toString() {
- return String.format("[%s.xml %s %s%d %s %s %s%s%s%s%s%s%s]",
+ return String.format("[%s.xml %s %s%d %s %s %s%s%s%s%s%s]",
mXmlName,
mLocale,
(mOrientation == 1 ? "port" : "land"), mWidth,
modeName(mMode),
EditorInfoCompatUtils.imeOptionsName(mImeAction),
- colorSchemeName(mColorScheme),
(mNavigateAction ? " navigateAction" : ""),
(mPasswordInput ? " passwordInput" : ""),
(mHasSettingsKey ? " hasSettingsKey" : ""),
@@ -189,12 +188,4 @@ public class KeyboardId {
}
return null;
}
-
- public static String colorSchemeName(int colorScheme) {
- switch (colorScheme) {
- case KeyboardView.COLOR_SCHEME_WHITE: return "white";
- case KeyboardView.COLOR_SCHEME_BLACK: return "black";
- }
- return null;
- }
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 157337cca..1ad5b08eb 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -26,6 +26,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
+import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
import com.android.inputmethod.keyboard.internal.Key;
import com.android.inputmethod.keyboard.internal.ModifierKeyState;
@@ -53,7 +54,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
R.style.KeyboardTheme_Stone,
R.style.KeyboardTheme_Stone_Bold,
R.style.KeyboardTheme_Gingerbread,
- R.style.KeyboardTheme_Honeycomb,
+ R.style.KeyboardTheme_IceCreamSandwich,
};
private SubtypeSwitcher mSubtypeSwitcher;
@@ -258,7 +259,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private KeyboardId getKeyboardId(EditorInfo attribute, boolean isSymbols) {
final int mode = Utils.getKeyboardMode(attribute);
final boolean hasVoiceKey = hasVoiceKey(isSymbols);
- final int charColorId = getColorScheme();
final int xmlId;
final boolean enableShiftLock;
@@ -291,9 +291,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mKeyboardWidth = res.getDisplayMetrics().widthPixels;
final Locale locale = mSubtypeSwitcher.getInputLocale();
return new KeyboardId(
- res.getResourceEntryName(xmlId), xmlId, charColorId, locale, orientation,
- mKeyboardWidth, mode, attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey,
- enableShiftLock);
+ res.getResourceEntryName(xmlId), xmlId, locale, orientation, mKeyboardWidth,
+ mode, attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, enableShiftLock);
}
private KeyboardId makeSiblingKeyboardId(KeyboardId base, int alphabet, int phone) {
@@ -761,6 +760,11 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mKeyboardView = (LatinKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
mKeyboardView.setOnKeyboardActionListener(mInputMethodService);
+
+ // This always needs to be set since the accessibility state can
+ // potentially change without the input view being re-created.
+ AccessibleKeyboardViewProxy.setView(mKeyboardView);
+
return mCurrentInputView;
}
@@ -788,11 +792,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
}
- private int getColorScheme() {
- return (mKeyboardView != null)
- ? mKeyboardView.getColorScheme() : KeyboardView.COLOR_SCHEME_WHITE;
- }
-
public void onAutoCorrectionStateChanged(boolean isAutoCorrection) {
if (mIsAutoCorrectionActive != isAutoCorrection) {
mIsAutoCorrectionActive = isAutoCorrection;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index c372281c2..a6aef27e0 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -42,9 +42,12 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.PopupWindow;
import android.widget.TextView;
+import com.android.inputmethod.accessibility.AccessibilityUtils;
+import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.compat.FrameLayoutCompatUtils;
import com.android.inputmethod.keyboard.internal.Key;
import com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder;
@@ -62,7 +65,6 @@ import java.util.WeakHashMap;
* presses and touch movements.
*
* @attr ref R.styleable#KeyboardView_backgroundDimAmount
- * @attr ref R.styleable#KeyboardView_colorScheme
* @attr ref R.styleable#KeyboardView_keyBackground
* @attr ref R.styleable#KeyboardView_keyHysteresisDistance
* @attr ref R.styleable#KeyboardView_keyLetterRatio
@@ -91,9 +93,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = true;
private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true;
- public static final int COLOR_SCHEME_WHITE = 0;
- public static final int COLOR_SCHEME_BLACK = 1;
-
// Timing constants
private final int mKeyRepeatInterval;
@@ -109,7 +108,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private final float mKeyLabelRatio;
private final float mKeyHintLetterRatio;
private final float mKeyUppercaseLetterRatio;
- private final int mColorScheme;
private final int mShadowColor;
private final float mShadowRadius;
private final Drawable mKeyBackground;
@@ -356,7 +354,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mShadowRadius = a.getFloat(R.styleable.KeyboardView_shadowRadius, 0f);
// TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount)
mBackgroundDimAmount = a.getFloat(R.styleable.KeyboardView_backgroundDimAmount, 0.5f);
- mColorScheme = a.getInt(R.styleable.KeyboardView_colorScheme, COLOR_SCHEME_WHITE);
a.recycle();
final Resources res = getResources();
@@ -565,10 +562,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
return mShowKeyPreviewPopup;
}
- public int getColorScheme() {
- return mColorScheme;
- }
-
/**
* When enabled, calls to {@link KeyboardActionListener#onCodeInput} will include key
* codes for adjacent keys. When disabled, only the primary key code will be
@@ -835,16 +828,18 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
// For characters, use large font. For labels like "Done", use small font.
final int labelSize;
final Typeface labelStyle;
+ if ((keyLabelOption & Key.LABEL_OPTION_FONT_NORMAL) != 0) {
+ labelStyle = Typeface.DEFAULT;
+ } else if ((keyLabelOption & Key.LABEL_OPTION_FONT_FIXED_WIDTH) != 0) {
+ labelStyle = Typeface.MONOSPACE;
+ } else {
+ labelStyle = mKeyTextStyle;
+ }
if (label.length() > 1) {
- labelSize = mKeyLabelSize;
- if ((keyLabelOption & Key.LABEL_OPTION_FONT_NORMAL) != 0) {
- labelStyle = Typeface.DEFAULT;
- } else {
- labelStyle = Typeface.DEFAULT_BOLD;
- }
+ labelSize = (keyLabelOption & Key.LABEL_OPTION_FOLLOW_KEY_LETTER_RATIO) != 0
+ ? mKeyLetterSize : mKeyLabelSize;
} else {
labelSize = mKeyLetterSize;
- labelStyle = mKeyTextStyle;
}
paint.setTextSize(labelSize);
paint.setTypeface(labelStyle);
@@ -978,7 +973,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
if (key.mLabel != null) {
// TODO Should take care of temporaryShiftLabel here.
previewText.setCompoundDrawables(null, null, null, null);
- previewText.setText(adjustCase(tracker.getPreviewText(key)));
if (key.mLabel.length() > 1) {
previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyLetterSize);
previewText.setTypeface(Typeface.DEFAULT_BOLD);
@@ -986,6 +980,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSize);
previewText.setTypeface(mKeyTextStyle);
}
+ previewText.setText(adjustCase(tracker.getPreviewText(key)));
} else {
final Drawable previewIcon = key.getPreviewIcon();
previewText.setCompoundDrawables(null, null, null,
@@ -1127,7 +1122,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
miniKeyboardView.setKeyboard(keyboard);
container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
return miniKeyboardView;
}
@@ -1335,4 +1330,37 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
public boolean handleBack() {
return dismissMiniKeyboard();
}
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
+ return AccessibleKeyboardViewProxy.getInstance().dispatchTouchEvent(event)
+ || super.dispatchTouchEvent(event);
+ }
+
+ return super.dispatchTouchEvent(event);
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
+ final PointerTracker tracker = getPointerTracker(0);
+ return AccessibleKeyboardViewProxy.getInstance().dispatchPopulateAccessibilityEvent(
+ event, tracker) || super.dispatchPopulateAccessibilityEvent(event);
+ }
+
+ return super.dispatchPopulateAccessibilityEvent(event);
+ }
+
+ public boolean onHoverEvent(MotionEvent event) {
+ // Since reflection doesn't support calling superclass methods, this
+ // method checks for the existence of onHoverEvent() in the View class
+ // before returning a value.
+ if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
+ final PointerTracker tracker = getPointerTracker(0);
+ return AccessibleKeyboardViewProxy.getInstance().onHoverEvent(event, tracker);
+ }
+
+ return false;
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index e741625ca..0329ee2b3 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -60,6 +60,7 @@ public class LatinKeyboard extends Keyboard {
private final Drawable mSpaceIcon;
private final Drawable mSpacePreviewIcon;
private final int mSpaceKeyIndex;
+ private final boolean mAutoCorrectionSpacebarLedEnabled;
private final Drawable mAutoCorrectionSpacebarLedIcon;
private final Drawable mSpacebarArrowLeftIcon;
private final Drawable mSpacebarArrowRightIcon;
@@ -123,6 +124,8 @@ public class LatinKeyboard extends Keyboard {
final TypedArray a = context.obtainStyledAttributes(
null, R.styleable.LatinKeyboard, R.attr.latinKeyboardStyle, R.style.LatinKeyboard);
+ mAutoCorrectionSpacebarLedEnabled = a.getBoolean(
+ R.styleable.LatinKeyboard_autoCorrectionSpacebarLedEnabled, false);
mAutoCorrectionSpacebarLedIcon = a.getDrawable(
R.styleable.LatinKeyboard_autoCorrectionSpacebarLedIcon);
mDisabledShortcutIcon = a.getDrawable(R.styleable.LatinKeyboard_disabledShortcutIcon);
@@ -179,7 +182,7 @@ public class LatinKeyboard extends Keyboard {
}
public boolean needsAutoCorrectionSpacebarLed() {
- return mAutoCorrectionSpacebarLedIcon != null;
+ return mAutoCorrectionSpacebarLedEnabled;
}
/**
@@ -212,7 +215,7 @@ public class LatinKeyboard extends Keyboard {
}
// Layout local language name and left and right arrow on spacebar.
- private static String layoutSpacebar(Paint paint, Locale locale, Drawable lArrow,
+ private static String layoutSpacebar(Paint paint, Locale locale, Drawable icon, Drawable lArrow,
Drawable rArrow, int width, int height, float origTextSize) {
final float arrowWidth = lArrow.getIntrinsicWidth();
final float arrowHeight = lArrow.getIntrinsicHeight();
@@ -249,7 +252,9 @@ public class LatinKeyboard extends Keyboard {
paint.setTextSize(textSize);
// Place left and right arrow just before and after language text.
- final float baseline = height * SPACEBAR_LANGUAGE_BASELINE;
+ final float textHeight = -paint.ascent() + paint.descent();
+ final float baseline = (icon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
+ : height / 2 + textHeight / 2;
final int top = (int)(baseline - arrowHeight);
final float remains = (width - textWidth) / 2;
lArrow.setBounds((int)(remains - arrowWidth), top, (int)remains, (int)baseline);
@@ -300,7 +305,7 @@ public class LatinKeyboard extends Keyboard {
defaultTextSize = 14;
}
- final String language = layoutSpacebar(paint, inputLocale,
+ final String language = layoutSpacebar(paint, inputLocale, mSpaceIcon,
mSpacebarArrowLeftIcon, mSpacebarArrowRightIcon, width, height,
getTextSizeFromTheme(mTheme, textStyle, defaultTextSize));
diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java
index 2085404dc..6180f09c1 100644
--- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java
@@ -78,15 +78,12 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel {
final int pointY = parentKey.mY;
final int miniKeyboardLeft = pointX - miniKeyboard.getDefaultCoordX()
+ parentKeyboardView.getPaddingLeft();
- final int miniKeyboardX = Math.max(0, Math.min(miniKeyboardLeft,
+ final int x = Math.max(0, Math.min(miniKeyboardLeft,
parentKeyboardView.getWidth() - miniKeyboard.getMinWidth()))
- container.getPaddingLeft() + mCoordinates[0];
- final int miniKeyboardY = pointY - parentKeyboard.getVerticalGap()
+ final int y = pointY - parentKeyboard.getVerticalGap()
- (container.getMeasuredHeight() - container.getPaddingBottom())
+ parentKeyboardView.getPaddingTop() + mCoordinates[1];
- final int x = miniKeyboardX;
- final int y = parentKeyboardView.isKeyPreviewPopupEnabled() &&
- miniKeyboard.isOneRowKeyboard() && keyPreviewY >= 0 ? keyPreviewY : miniKeyboardY;
if (miniKeyboard.setShifted(parentKeyboard.isShiftedOrShiftLocked())) {
invalidateAllKeys();
diff --git a/java/src/com/android/inputmethod/keyboard/PopupPanel.java b/java/src/com/android/inputmethod/keyboard/PopupPanel.java
index 72fa7406a..48454679e 100644
--- a/java/src/com/android/inputmethod/keyboard/PopupPanel.java
+++ b/java/src/com/android/inputmethod/keyboard/PopupPanel.java
@@ -30,6 +30,7 @@ public interface PopupPanel {
* @param keyPreviewY the Y-coordinate of key preview
* @param window PopupWindow to be used to show this popup panel
*/
+ // TODO: Remove keyPreviewY from argument.
public void showPanel(KeyboardView parentKeyboardView, Key parentKey,
PointerTracker tracker, int keyPreviewY, PopupWindow window);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/Key.java b/java/src/com/android/inputmethod/keyboard/internal/Key.java
index 5470067dc..ebd80be5e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/Key.java
@@ -49,8 +49,10 @@ public class Key {
public static final int LABEL_OPTION_ALIGN_RIGHT = 0x02;
public static final int LABEL_OPTION_ALIGN_BOTTOM = 0x08;
public static final int LABEL_OPTION_FONT_NORMAL = 0x10;
- private static final int LABEL_OPTION_POPUP_HINT = 0x20;
- private static final int LABEL_OPTION_HAS_UPPERCASE_LETTER = 0x40;
+ public static final int LABEL_OPTION_FONT_FIXED_WIDTH = 0x20;
+ public static final int LABEL_OPTION_FOLLOW_KEY_LETTER_RATIO = 0x40;
+ private static final int LABEL_OPTION_POPUP_HINT = 0x80;
+ private static final int LABEL_OPTION_HAS_UPPERCASE_LETTER = 0x100;
/** Icon to display instead of a label. Icon takes precedence over a label */
private Drawable mIcon;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
index 7be738ceb..37b36825a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -16,13 +16,17 @@
package com.android.inputmethod.keyboard.internal;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.util.Log;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.R;
public class KeyboardIconsSet {
+ private static final String TAG = KeyboardIconsSet.class.getSimpleName();
+
public static final int ICON_UNDEFINED = 0;
// This should be aligned with Keyboard.keyIcon enum.
@@ -46,18 +50,15 @@ public class KeyboardIconsSet {
private static final int ICON_NUM8_KEY = 18;
private static final int ICON_NUM9_KEY = 19;
private static final int ICON_NUM0_KEY = 20;
- private static final int ICON_NUM_STAR_KEY = 21;
- private static final int ICON_NUM_POUND_KEY = 22;
- private static final int ICON_NUM_ALT_KEY = 23;
// This should be aligned with Keyboard.keyIconShifted enum.
- private static final int ICON_SHIFTED_SHIFT_KEY = 24;
+ private static final int ICON_SHIFTED_SHIFT_KEY = 21;
// This should be aligned with Keyboard.keyIconPreview enum.
- private static final int ICON_PREVIEW_SPACE_KEY = 25;
- private static final int ICON_PREVIEW_TAB_KEY = 26;
- private static final int ICON_PREVIEW_SETTINGS_KEY = 27;
- private static final int ICON_PREVIEW_SHORTCUT_KEY = 28;
+ private static final int ICON_PREVIEW_SPACE_KEY = 22;
+ private static final int ICON_PREVIEW_TAB_KEY = 23;
+ private static final int ICON_PREVIEW_SETTINGS_KEY = 24;
+ private static final int ICON_PREVIEW_SHORTCUT_KEY = 25;
- private static final int ICON_LAST = 28;
+ private static final int ICON_LAST = 25;
private final Drawable mIcons[] = new Drawable[ICON_LAST + 1];
@@ -103,12 +104,6 @@ public class KeyboardIconsSet {
return ICON_NUM9_KEY;
case R.styleable.Keyboard_iconNum0Key:
return ICON_NUM0_KEY;
- case R.styleable.Keyboard_iconNumStarKey:
- return ICON_NUM_STAR_KEY;
- case R.styleable.Keyboard_iconNumPoundKey:
- return ICON_NUM_POUND_KEY;
- case R.styleable.Keyboard_iconNumAltKey:
- return ICON_NUM_ALT_KEY;
case R.styleable.Keyboard_iconShiftedShiftKey:
return ICON_SHIFTED_SHIFT_KEY;
case R.styleable.Keyboard_iconPreviewSpaceKey:
@@ -130,9 +125,13 @@ public class KeyboardIconsSet {
final int attrIndex = keyboardAttrs.getIndex(i);
final int iconId = getIconId(attrIndex);
if (iconId != ICON_UNDEFINED) {
- final Drawable icon = keyboardAttrs.getDrawable(attrIndex);
- Keyboard.setDefaultBounds(icon);
- mIcons[iconId] = icon;
+ try {
+ final Drawable icon = keyboardAttrs.getDrawable(attrIndex);
+ Keyboard.setDefaultBounds(icon);
+ mIcons[iconId] = icon;
+ } catch (Resources.NotFoundException e) {
+ Log.w(TAG, "Drawable resource for icon #" + iconId + " not found");
+ }
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java
index 9525b0e00..d5b364818 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java
@@ -90,14 +90,14 @@ import java.util.List;
* You can declare Key style and specify styles within Key tags.
* <pre>
* &gt;switch&lt;
- * &gt;case colorScheme="white"&lt;
- * &gt;key-style styleName="shift-key" parentStyle="modifier-key"
- * keyIcon="@drawable/sym_keyboard_shift"
+ * &gt;case mode="email"&lt;
+ * &gt;key-style styleName="f1-key" parentStyle="modifier-key"
+ * keyLabel=".com"
* /&lt;
* &gt;/case&lt;
- * &gt;case colorScheme="black"&lt;
- * &gt;key-style styleName="shift-key" parentStyle="modifier-key"
- * keyIcon="@drawable/sym_bkeyboard_shift"
+ * &gt;case mode="url"&lt;
+ * &gt;key-style styleName="f1-key" parentStyle="modifier-key"
+ * keyLabel="http://"
* /&lt;
* &gt;/case&lt;
* &gt;/switch&lt;
@@ -126,6 +126,8 @@ public class KeyboardParser {
private final Context mContext;
private final Resources mResources;
+ private int mKeyboardTopPadding;
+ private int mKeyboardBottomPadding;
private int mHorizontalEdgesPadding;
private int mCurrentX = 0;
private int mCurrentY = 0;
@@ -234,6 +236,10 @@ public class KeyboardParser {
R.styleable.Keyboard_Key_maxPopupKeyboardColumn, 5));
mKeyboard.mIconsSet.loadIcons(keyboardAttr);
+ mKeyboardTopPadding = keyboardAttr.getDimensionPixelSize(
+ R.styleable.Keyboard_keyboardTopPadding, 0);
+ mKeyboardBottomPadding = keyboardAttr.getDimensionPixelSize(
+ R.styleable.Keyboard_keyboardBottomPadding, 0);
} finally {
keyAttr.recycle();
keyboardAttr.recycle();
@@ -487,8 +493,6 @@ public class KeyboardParser {
R.styleable.Keyboard_Case_voiceKeyEnabled, id.mVoiceKeyEnabled);
final boolean voiceKeyMatched = matchBoolean(a,
R.styleable.Keyboard_Case_hasVoiceKey, id.mHasVoiceKey);
- final boolean colorSchemeMatched = matchInteger(viewAttr,
- R.styleable.KeyboardView_colorScheme, id.mColorScheme);
// As noted at {@link KeyboardId} class, we are interested only in enum value masked by
// {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and
// {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching
@@ -503,14 +507,11 @@ public class KeyboardParser {
R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
final boolean selected = modeMatched && navigateActionMatched && passwordInputMatched
&& settingsKeyMatched && voiceEnabledMatched && voiceKeyMatched
- && colorSchemeMatched && imeActionMatched && localeCodeMatched
- && languageCodeMatched && countryCodeMatched;
+ && imeActionMatched && localeCodeMatched && languageCodeMatched
+ && countryCodeMatched;
- if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
+ if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
- textAttr(KeyboardId.colorSchemeName(
- viewAttr.getInt(
- R.styleable.KeyboardView_colorScheme, -1)), "colorScheme"),
booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"),
booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"),
@@ -607,7 +608,7 @@ public class KeyboardParser {
}
private void startKeyboard() {
- mCurrentY += (int)mResources.getDimension(R.dimen.keyboard_top_padding);
+ mCurrentY += mKeyboardTopPadding;
}
private void startRow(Row row) {
@@ -631,7 +632,7 @@ public class KeyboardParser {
}
private void endKeyboard(int defaultVerticalGap) {
- mCurrentY += (int)mResources.getDimension(R.dimen.keyboard_bottom_padding);
+ mCurrentY += mKeyboardBottomPadding;
mTotalHeight = mCurrentY - defaultVerticalGap;
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 1645b1678..9c6465dd2 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -53,6 +53,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.InputConnection;
+import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.compat.CompatUtils;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
import com.android.inputmethod.compat.InputConnectionCompatUtils;
@@ -353,6 +354,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
SubtypeSwitcher.init(this, prefs);
KeyboardSwitcher.init(this, prefs);
Recorrection.init(this, prefs);
+ AccessibilityUtils.init(this, prefs);
super.onCreate();