aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/accessibility
diff options
context:
space:
mode:
authorAmin Bandali <bandali@kelar.org>2024-12-16 21:45:41 -0500
committerAmin Bandali <bandali@kelar.org>2025-01-11 14:17:35 -0500
commite9a0e66716dab4dd3184d009d8920de1961efdfa (patch)
tree02dcc096643d74645bf28459c2834c3d4a2ad7f2 /java/src/com/android/inputmethod/accessibility
parentfb3b9360d70596d7e921de8bf7d3ca99564a077e (diff)
downloadlatinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.gz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.xz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.zip
Rename to Kelar Keyboard (org.kelar.inputmethod.latin)
Diffstat (limited to 'java/src/com/android/inputmethod/accessibility')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java67
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java266
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java365
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java326
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java339
-rw-r--r--java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java293
-rw-r--r--java/src/com/android/inputmethod/accessibility/MoreKeysKeyboardAccessibilityDelegate.java120
7 files changed, 0 insertions, 1776 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java b/java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java
deleted file mode 100644
index 37d910edb..000000000
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityLongPressTimer.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 performLongClickOn(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.performLongClickOn((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/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
deleted file mode 100644
index 31e142e72..000000000
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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.media.AudioManager;
-import android.os.Build;
-import android.os.SystemClock;
-import android.provider.Settings;
-import androidx.core.view.accessibility.AccessibilityEventCompat;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.inputmethod.EditorInfo;
-
-import com.android.inputmethod.compat.SettingsSecureCompatUtils;
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.utils.InputTypeUtils;
-
-public final class AccessibilityUtils {
- private static final String TAG = AccessibilityUtils.class.getSimpleName();
- private static final String CLASS = AccessibilityUtils.class.getName();
- private static final String PACKAGE =
- AccessibilityUtils.class.getPackage().getName();
-
- private static final AccessibilityUtils sInstance = new AccessibilityUtils();
-
- private Context mContext;
- private AccessibilityManager mAccessibilityManager;
- private AudioManager mAudioManager;
-
- /** The most recent auto-correction. */
- private String mAutoCorrectionWord;
-
- /** The most recent typed word for auto-correction. */
- private String mTypedWord;
-
- /*
- * 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(final Context context) {
- if (!ENABLE_ACCESSIBILITY) return;
-
- // These only need to be initialized if the kill switch is off.
- sInstance.initInternal(context);
- }
-
- public static AccessibilityUtils getInstance() {
- return sInstance;
- }
-
- private AccessibilityUtils() {
- // This class is not publicly instantiable.
- }
-
- private void initInternal(final Context context) {
- mContext = context;
- mAccessibilityManager =
- (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- }
-
- /**
- * Returns {@code true} if accessibility is enabled. Currently, this means
- * that the kill switch is off and system accessibility is turned on.
- *
- * @return {@code true} if accessibility is enabled.
- */
- public boolean isAccessibilityEnabled() {
- return ENABLE_ACCESSIBILITY && mAccessibilityManager.isEnabled();
- }
-
- /**
- * Returns {@code true} if touch exploration is enabled. Currently, this
- * means that the kill switch is off, the device supports touch exploration,
- * and system accessibility is turned on.
- *
- * @return {@code true} if touch exploration is enabled.
- */
- public boolean isTouchExplorationEnabled() {
- return isAccessibilityEnabled() && mAccessibilityManager.isTouchExplorationEnabled();
- }
-
- /**
- * 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 static boolean isTouchExplorationEvent(final MotionEvent event) {
- final int action = event.getAction();
- return action == MotionEvent.ACTION_HOVER_ENTER
- || action == MotionEvent.ACTION_HOVER_EXIT
- || action == MotionEvent.ACTION_HOVER_MOVE;
- }
-
- /**
- * Returns whether the device should obscure typed password characters.
- * Typically this means speaking "dot" in place of non-control characters.
- *
- * @return {@code true} if the device should obscure password characters.
- */
- @SuppressWarnings("deprecation")
- public boolean shouldObscureInput(final EditorInfo editorInfo) {
- if (editorInfo == null) return false;
-
- // The user can optionally force speaking passwords.
- if (SettingsSecureCompatUtils.ACCESSIBILITY_SPEAK_PASSWORD != null) {
- final boolean speakPassword = Settings.Secure.getInt(mContext.getContentResolver(),
- SettingsSecureCompatUtils.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
- if (speakPassword) return false;
- }
-
- // Always speak if the user is listening through headphones.
- if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) {
- return false;
- }
-
- // Don't speak if the IME is connected to a password field.
- return InputTypeUtils.isPasswordInputType(editorInfo.inputType);
- }
-
- /**
- * Sets the current auto-correction word and typed word. These may be used
- * to provide the user with a spoken description of what auto-correction
- * will occur when a key is typed.
- *
- * @param suggestedWords the list of suggested auto-correction words
- */
- public void setAutoCorrection(final SuggestedWords suggestedWords) {
- if (suggestedWords.mWillAutoCorrect) {
- mAutoCorrectionWord = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION);
- final SuggestedWords.SuggestedWordInfo typedWordInfo = suggestedWords.mTypedWordInfo;
- if (null == typedWordInfo) {
- mTypedWord = null;
- } else {
- mTypedWord = typedWordInfo.mWord;
- }
- } else {
- mAutoCorrectionWord = null;
- mTypedWord = null;
- }
- }
-
- /**
- * Obtains a description for an auto-correction key, taking into account the
- * currently typed word and auto-correction.
- *
- * @param keyCodeDescription spoken description of the key that will insert
- * an auto-correction
- * @param shouldObscure whether the key should be obscured
- * @return a description including a description of the auto-correction, if
- * needed
- */
- public String getAutoCorrectionDescription(
- final String keyCodeDescription, final boolean shouldObscure) {
- if (!TextUtils.isEmpty(mAutoCorrectionWord)) {
- if (!TextUtils.equals(mAutoCorrectionWord, mTypedWord)) {
- if (shouldObscure) {
- // This should never happen, but just in case...
- return mContext.getString(R.string.spoken_auto_correct_obscured,
- keyCodeDescription);
- }
- return mContext.getString(R.string.spoken_auto_correct, keyCodeDescription,
- mTypedWord, mAutoCorrectionWord);
- }
- }
-
- return keyCodeDescription;
- }
-
- /**
- * Sends the specified text to the {@link AccessibilityManager} to be
- * spoken.
- *
- * @param view The source view.
- * @param text The text to speak.
- */
- public void announceForAccessibility(final View view, final 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();
-
- event.setPackageName(PACKAGE);
- event.setClassName(CLASS);
- event.setEventTime(SystemClock.uptimeMillis());
- event.setEnabled(true);
- event.getText().add(text);
-
- // Platforms starting at SDK version 16 (Build.VERSION_CODES.JELLY_BEAN) should use
- // announce events.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- event.setEventType(AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
- } else {
- event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
- }
-
- final ViewParent viewParent = view.getParent();
- if ((viewParent == null) || !(viewParent instanceof ViewGroup)) {
- Log.e(TAG, "Failed to obtain ViewParent in announceForAccessibility");
- return;
- }
-
- viewParent.requestSendAccessibilityEvent(view, event);
- }
-
- /**
- * Handles speaking the "connect a headset to hear passwords" notification
- * when connecting to a password field.
- *
- * @param view The source view.
- * @param editorInfo The input connection's editor info attribute.
- * @param restarting Whether the connection is being restarted.
- */
- public void onStartInputViewInternal(final View view, final EditorInfo editorInfo,
- final boolean restarting) {
- if (shouldObscureInput(editorInfo)) {
- final CharSequence text = mContext.getText(R.string.spoken_use_headphones);
- announceForAccessibility(view, text);
- }
- }
-
- /**
- * Sends the specified {@link AccessibilityEvent} if accessibility is
- * enabled. No operation if accessibility is disabled.
- *
- * @param event The event to send.
- */
- public void requestSendAccessibilityEvent(final AccessibilityEvent event) {
- if (mAccessibilityManager.isEnabled()) {
- mAccessibilityManager.sendAccessibilityEvent(event);
- }
- }
-}
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
deleted file mode 100644
index bbda9f8e2..000000000
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * 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.res.Resources;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseIntArray;
-import android.view.inputmethod.EditorInfo;
-
-import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.common.Constants;
-import com.android.inputmethod.latin.common.StringUtils;
-
-import java.util.Locale;
-
-final class KeyCodeDescriptionMapper {
- private static final String TAG = KeyCodeDescriptionMapper.class.getSimpleName();
- private static final String SPOKEN_LETTER_RESOURCE_NAME_FORMAT = "spoken_accented_letter_%04X";
- private static final String SPOKEN_SYMBOL_RESOURCE_NAME_FORMAT = "spoken_symbol_%04X";
- private static final String SPOKEN_EMOJI_RESOURCE_NAME_FORMAT = "spoken_emoji_%04X";
- private static final String SPOKEN_EMOTICON_RESOURCE_NAME_PREFIX = "spoken_emoticon";
- private static final String SPOKEN_EMOTICON_CODE_POINT_FORMAT = "_%02X";
-
- // The resource ID of the string spoken for obscured keys
- private static final int OBSCURED_KEY_RES_ID = R.string.spoken_description_dot;
-
- private static final KeyCodeDescriptionMapper sInstance = new KeyCodeDescriptionMapper();
-
- public static KeyCodeDescriptionMapper getInstance() {
- return sInstance;
- }
-
- // Sparse array of spoken description resource IDs indexed by key codes
- private final SparseIntArray mKeyCodeMap = new SparseIntArray();
-
- private KeyCodeDescriptionMapper() {
- // Special non-character codes defined in Keyboard
- mKeyCodeMap.put(Constants.CODE_SPACE, R.string.spoken_description_space);
- mKeyCodeMap.put(Constants.CODE_DELETE, R.string.spoken_description_delete);
- mKeyCodeMap.put(Constants.CODE_ENTER, R.string.spoken_description_return);
- mKeyCodeMap.put(Constants.CODE_SETTINGS, R.string.spoken_description_settings);
- mKeyCodeMap.put(Constants.CODE_SHIFT, R.string.spoken_description_shift);
- mKeyCodeMap.put(Constants.CODE_SHORTCUT, R.string.spoken_description_mic);
- mKeyCodeMap.put(Constants.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol);
- mKeyCodeMap.put(Constants.CODE_TAB, R.string.spoken_description_tab);
- mKeyCodeMap.put(Constants.CODE_LANGUAGE_SWITCH,
- R.string.spoken_description_language_switch);
- mKeyCodeMap.put(Constants.CODE_ACTION_NEXT, R.string.spoken_description_action_next);
- mKeyCodeMap.put(Constants.CODE_ACTION_PREVIOUS,
- R.string.spoken_description_action_previous);
- mKeyCodeMap.put(Constants.CODE_EMOJI, R.string.spoken_description_emoji);
- // Because the upper-case and lower-case mappings of the following letters is depending on
- // the locale, the upper case descriptions should be defined here. The lower case
- // descriptions are handled in {@link #getSpokenLetterDescriptionId(Context,int)}.
- // U+0049: "I" LATIN CAPITAL LETTER I
- // U+0069: "i" LATIN SMALL LETTER I
- // U+0130: "İ" LATIN CAPITAL LETTER I WITH DOT ABOVE
- // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
- mKeyCodeMap.put(0x0049, R.string.spoken_letter_0049);
- mKeyCodeMap.put(0x0130, R.string.spoken_letter_0130);
- }
-
- /**
- * Returns the localized description of the action performed by a specified
- * key based on the current keyboard state.
- *
- * @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.
- * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured.
- * @return a character sequence describing the action performed by pressing the key
- */
- public String getDescriptionForKey(final Context context, final Keyboard keyboard,
- final Key key, final boolean shouldObscure) {
- final int code = key.getCode();
-
- if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
- final String description = getDescriptionForSwitchAlphaSymbol(context, keyboard);
- if (description != null) {
- return description;
- }
- }
-
- if (code == Constants.CODE_SHIFT) {
- return getDescriptionForShiftKey(context, keyboard);
- }
-
- if (code == Constants.CODE_ENTER) {
- // The following function returns the correct description in all action and
- // regular enter cases, taking care of all modes.
- return getDescriptionForActionKey(context, keyboard, key);
- }
-
- if (code == Constants.CODE_OUTPUT_TEXT) {
- final String outputText = key.getOutputText();
- final String description = getSpokenEmoticonDescription(context, outputText);
- return TextUtils.isEmpty(description) ? outputText : description;
- }
-
- // Just attempt to speak the description.
- if (code != Constants.CODE_UNSPECIFIED) {
- // If the key description should be obscured, now is the time to do it.
- final boolean isDefinedNonCtrl = Character.isDefined(code)
- && !Character.isISOControl(code);
- if (shouldObscure && isDefinedNonCtrl) {
- return context.getString(OBSCURED_KEY_RES_ID);
- }
- final String description = getDescriptionForCodePoint(context, code);
- if (description != null) {
- return description;
- }
- if (!TextUtils.isEmpty(key.getLabel())) {
- return key.getLabel();
- }
- return context.getString(R.string.spoken_description_unknown);
- }
- 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 static String getDescriptionForSwitchAlphaSymbol(final Context context,
- final Keyboard keyboard) {
- final KeyboardId keyboardId = keyboard.mId;
- final int elementId = keyboardId.mElementId;
- final int resId;
-
- switch (elementId) {
- case KeyboardId.ELEMENT_ALPHABET:
- case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED:
- case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
- case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
- case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
- resId = R.string.spoken_description_to_symbol;
- break;
- case KeyboardId.ELEMENT_SYMBOLS:
- case KeyboardId.ELEMENT_SYMBOLS_SHIFTED:
- resId = R.string.spoken_description_to_alpha;
- break;
- case KeyboardId.ELEMENT_PHONE:
- resId = R.string.spoken_description_to_symbol;
- break;
- case KeyboardId.ELEMENT_PHONE_SYMBOLS:
- resId = R.string.spoken_description_to_numeric;
- break;
- default:
- Log.e(TAG, "Missing description for keyboard element ID:" + elementId);
- return null;
- }
- return context.getString(resId);
- }
-
- /**
- * Returns a context-sensitive description of the "Shift" key.
- *
- * @param context The package's context.
- * @param keyboard The keyboard on which the key resides.
- * @return A context-sensitive description of the "Shift" key.
- */
- private static String getDescriptionForShiftKey(final Context context,
- final Keyboard keyboard) {
- final KeyboardId keyboardId = keyboard.mId;
- final int elementId = keyboardId.mElementId;
- final int resId;
-
- switch (elementId) {
- case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
- case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
- resId = R.string.spoken_description_caps_lock;
- break;
- case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED:
- case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
- resId = R.string.spoken_description_shift_shifted;
- break;
- case KeyboardId.ELEMENT_SYMBOLS:
- resId = R.string.spoken_description_symbols_shift;
- break;
- case KeyboardId.ELEMENT_SYMBOLS_SHIFTED:
- resId = R.string.spoken_description_symbols_shift_shifted;
- break;
- default:
- resId = R.string.spoken_description_shift;
- }
- return context.getString(resId);
- }
-
- /**
- * Returns a context-sensitive description of the "Enter" action key.
- *
- * @param context The package's context.
- * @param keyboard The keyboard on which the key resides.
- * @param key The key to describe.
- * @return Returns a context-sensitive description of the "Enter" action key.
- */
- private static String getDescriptionForActionKey(final Context context, final Keyboard keyboard,
- final Key key) {
- final KeyboardId keyboardId = keyboard.mId;
- final int actionId = keyboardId.imeAction();
- final int resId;
-
- // Always use the label, if available.
- if (!TextUtils.isEmpty(key.getLabel())) {
- return key.getLabel().trim();
- }
-
- // Otherwise, use the action ID.
- switch (actionId) {
- case EditorInfo.IME_ACTION_SEARCH:
- resId = R.string.spoken_description_search;
- break;
- case EditorInfo.IME_ACTION_GO:
- resId = R.string.label_go_key;
- break;
- case EditorInfo.IME_ACTION_SEND:
- resId = R.string.label_send_key;
- break;
- case EditorInfo.IME_ACTION_NEXT:
- resId = R.string.label_next_key;
- break;
- case EditorInfo.IME_ACTION_DONE:
- resId = R.string.label_done_key;
- break;
- case EditorInfo.IME_ACTION_PREVIOUS:
- resId = R.string.label_previous_key;
- break;
- default:
- resId = R.string.spoken_description_return;
- }
- return context.getString(resId);
- }
-
- /**
- * Returns a localized character sequence describing what will happen when
- * the specified key is pressed based on its key code point.
- *
- * @param context The package's context.
- * @param codePoint The code point from which to obtain a description.
- * @return a character sequence describing the code point.
- */
- public String getDescriptionForCodePoint(final Context context, final int codePoint) {
- // If the key description should be obscured, now is the time to do it.
- final int index = mKeyCodeMap.indexOfKey(codePoint);
- if (index >= 0) {
- return context.getString(mKeyCodeMap.valueAt(index));
- }
- final String accentedLetter = getSpokenAccentedLetterDescription(context, codePoint);
- if (accentedLetter != null) {
- return accentedLetter;
- }
- // Here, <code>code</code> may be a base (non-accented) letter.
- final String unsupportedSymbol = getSpokenSymbolDescription(context, codePoint);
- if (unsupportedSymbol != null) {
- return unsupportedSymbol;
- }
- final String emojiDescription = getSpokenEmojiDescription(context, codePoint);
- if (emojiDescription != null) {
- return emojiDescription;
- }
- if (Character.isDefined(codePoint) && !Character.isISOControl(codePoint)) {
- return StringUtils.newSingleCodePointString(codePoint);
- }
- return null;
- }
-
- // TODO: Remove this method once TTS supports those accented letters' verbalization.
- private String getSpokenAccentedLetterDescription(final Context context, final int code) {
- final boolean isUpperCase = Character.isUpperCase(code);
- final int baseCode = isUpperCase ? Character.toLowerCase(code) : code;
- final int baseIndex = mKeyCodeMap.indexOfKey(baseCode);
- final int resId = (baseIndex >= 0) ? mKeyCodeMap.valueAt(baseIndex)
- : getSpokenDescriptionId(context, baseCode, SPOKEN_LETTER_RESOURCE_NAME_FORMAT);
- if (resId == 0) {
- return null;
- }
- final String spokenText = context.getString(resId);
- return isUpperCase ? context.getString(R.string.spoken_description_upper_case, spokenText)
- : spokenText;
- }
-
- // TODO: Remove this method once TTS supports those symbols' verbalization.
- private String getSpokenSymbolDescription(final Context context, final int code) {
- final int resId = getSpokenDescriptionId(context, code, SPOKEN_SYMBOL_RESOURCE_NAME_FORMAT);
- if (resId == 0) {
- return null;
- }
- final String spokenText = context.getString(resId);
- if (!TextUtils.isEmpty(spokenText)) {
- return spokenText;
- }
- // If a translated description is empty, fall back to unknown symbol description.
- return context.getString(R.string.spoken_symbol_unknown);
- }
-
- // TODO: Remove this method once TTS supports emoji verbalization.
- private String getSpokenEmojiDescription(final Context context, final int code) {
- final int resId = getSpokenDescriptionId(context, code, SPOKEN_EMOJI_RESOURCE_NAME_FORMAT);
- if (resId == 0) {
- return null;
- }
- final String spokenText = context.getString(resId);
- if (!TextUtils.isEmpty(spokenText)) {
- return spokenText;
- }
- // If a translated description is empty, fall back to unknown emoji description.
- return context.getString(R.string.spoken_emoji_unknown);
- }
-
- private int getSpokenDescriptionId(final Context context, final int code,
- final String resourceNameFormat) {
- final String resourceName = String.format(Locale.ROOT, resourceNameFormat, code);
- final Resources resources = context.getResources();
- // Note that the resource package name may differ from the context package name.
- final String resourcePackageName = resources.getResourcePackageName(
- R.string.spoken_description_unknown);
- final int resId = resources.getIdentifier(resourceName, "string", resourcePackageName);
- if (resId != 0) {
- mKeyCodeMap.append(code, resId);
- }
- return resId;
- }
-
- // TODO: Remove this method once TTS supports emoticon verbalization.
- private static String getSpokenEmoticonDescription(final Context context,
- final String outputText) {
- final StringBuilder sb = new StringBuilder(SPOKEN_EMOTICON_RESOURCE_NAME_PREFIX);
- final int textLength = outputText.length();
- for (int index = 0; index < textLength; index = outputText.offsetByCodePoints(index, 1)) {
- final int codePoint = outputText.codePointAt(index);
- sb.append(String.format(Locale.ROOT, SPOKEN_EMOTICON_CODE_POINT_FORMAT, codePoint));
- }
- final String resourceName = sb.toString();
- final Resources resources = context.getResources();
- // Note that the resource package name may differ from the context package name.
- final String resourcePackageName = resources.getResourcePackageName(
- R.string.spoken_description_unknown);
- final int resId = resources.getIdentifier(resourceName, "string", resourcePackageName);
- return (resId == 0) ? null : resources.getString(resId);
- }
-}
diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
deleted file mode 100644
index 5c03d26a9..000000000
--- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * 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.os.SystemClock;
-import androidx.core.view.AccessibilityDelegateCompat;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-
-import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.KeyDetector;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardView;
-
-/**
- * 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<KV> mAccessibilityNodeProvider;
- private Key mLastHoverKey;
-
- public static final int HOVER_EVENT_POINTER_ID = 0;
-
- public KeyboardAccessibilityDelegate(final KV keyboardView, final KeyDetector keyDetector) {
- super();
- mKeyboardView = keyboardView;
- mKeyDetector = keyDetector;
-
- // Ensure that the view has an accessibility delegate.
- ViewCompat.setAccessibilityDelegate(keyboardView, this);
- }
-
- /**
- * Called when the keyboard layout changes.
- * <p>
- * <b>Note:</b> This method will be called even if accessibility is not
- * enabled.
- * @param keyboard The keyboard that is being set to the wrapping view.
- */
- public void setKeyboard(final Keyboard keyboard) {
- if (keyboard == null) {
- return;
- }
- if (mAccessibilityNodeProvider != null) {
- mAccessibilityNodeProvider.setKeyboard(keyboard);
- }
- mKeyboard = keyboard;
- }
-
- protected final Keyboard getKeyboard() {
- return mKeyboard;
- }
-
- protected final void setLastHoverKey(final Key key) {
- mLastHoverKey = key;
- }
-
- protected final Key getLastHoverKey() {
- return mLastHoverKey;
- }
-
- /**
- * Sends a window state change event with the specified string resource id.
- *
- * @param resId The string resource id of the text to send with the event.
- */
- protected void sendWindowStateChanged(final int resId) {
- if (resId == 0) {
- return;
- }
- final Context context = mKeyboardView.getContext();
- sendWindowStateChanged(context.getString(resId));
- }
-
- /**
- * Sends a window state change event with the specified text.
- *
- * @param text The text to send with the event.
- */
- protected void sendWindowStateChanged(final String text) {
- final AccessibilityEvent stateChange = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- mKeyboardView.onInitializeAccessibilityEvent(stateChange);
- stateChange.getText().add(text);
- stateChange.setContentDescription(null);
-
- final ViewParent parent = mKeyboardView.getParent();
- if (parent != null) {
- parent.requestSendAccessibilityEvent(mKeyboardView, stateChange);
- }
- }
-
- /**
- * Delegate method for View.getAccessibilityNodeProvider(). This method is called in SDK
- * version 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) and higher to obtain the virtual
- * node hierarchy provider.
- *
- * @param host The host view for the provider.
- * @return The accessibility node provider for the current keyboard.
- */
- @Override
- public KeyboardAccessibilityNodeProvider<KV> getAccessibilityNodeProvider(final View host) {
- return getAccessibilityNodeProvider();
- }
-
- /**
- * @return A lazily-instantiated node provider for this view delegate.
- */
- protected KeyboardAccessibilityNodeProvider<KV> getAccessibilityNodeProvider() {
- // Instantiate the provide only when requested. Since the system
- // will call this method multiple times it is a good practice to
- // cache the provider instance.
- if (mAccessibilityNodeProvider == null) {
- mAccessibilityNodeProvider =
- new KeyboardAccessibilityNodeProvider<>(mKeyboardView, this);
- }
- return mAccessibilityNodeProvider;
- }
-
- /**
- * Get a key that a hover event is on.
- *
- * @param event The hover event.
- * @return key The key that the <code>event</code> is on.
- */
- protected final Key getHoverKeyOf(final MotionEvent event) {
- final int actionIndex = event.getActionIndex();
- final int x = (int)event.getX(actionIndex);
- final int y = (int)event.getY(actionIndex);
- return mKeyDetector.detectHitKey(x, y);
- }
-
- /**
- * Receives hover events when touch exploration is turned on in SDK versions ICS and higher.
- *
- * @param event The hover event.
- * @return {@code true} if the event is handled.
- */
- public boolean onHoverEvent(final MotionEvent event) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_HOVER_ENTER:
- onHoverEnter(event);
- break;
- case MotionEvent.ACTION_HOVER_MOVE:
- onHoverMove(event);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- onHoverExit(event);
- break;
- default:
- Log.w(getClass().getSimpleName(), "Unknown hover event: " + event);
- break;
- }
- return true;
- }
-
- /**
- * Process {@link MotionEvent#ACTION_HOVER_ENTER} event.
- *
- * @param event A hover enter event.
- */
- protected void onHoverEnter(final MotionEvent event) {
- final Key key = getHoverKeyOf(event);
- if (DEBUG_HOVER) {
- Log.d(TAG, "onHoverEnter: key=" + key);
- }
- if (key != null) {
- onHoverEnterTo(key);
- }
- setLastHoverKey(key);
- }
-
- /**
- * Process {@link MotionEvent#ACTION_HOVER_MOVE} event.
- *
- * @param event A hover move event.
- */
- protected void onHoverMove(final MotionEvent event) {
- final Key lastKey = getLastHoverKey();
- final Key key = getHoverKeyOf(event);
- if (key != lastKey) {
- if (lastKey != null) {
- onHoverExitFrom(lastKey);
- }
- if (key != null) {
- onHoverEnterTo(key);
- }
- }
- if (key != null) {
- onHoverMoveWithin(key);
- }
- setLastHoverKey(key);
- }
-
- /**
- * Process {@link MotionEvent#ACTION_HOVER_EXIT} event.
- *
- * @param event A hover exit event.
- */
- 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) {
- 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) {
- onHoverExitFrom(key);
- }
- setLastHoverKey(null);
- }
-
- /**
- * Perform click on a key.
- *
- * @param key A key to be registered.
- */
- public void performClickOn(final Key key) {
- if (DEBUG_HOVER) {
- Log.d(TAG, "performClickOn: key=" + key);
- }
- simulateTouchEvent(MotionEvent.ACTION_DOWN, key);
- simulateTouchEvent(MotionEvent.ACTION_UP, key);
- }
-
- /**
- * Simulating a touch event by injecting a synthesized touch event into {@link KeyboardView}.
- *
- * @param touchAction The action of the synthesizing touch event.
- * @param key The key that a synthesized touch event is on.
- */
- private void simulateTouchEvent(final int touchAction, final Key key) {
- final int x = key.getHitBox().centerX();
- final int y = key.getHitBox().centerY();
- final long eventTime = SystemClock.uptimeMillis();
- final MotionEvent touchEvent = MotionEvent.obtain(
- eventTime, eventTime, touchAction, x, y, 0 /* metaState */);
- mKeyboardView.onTouchEvent(touchEvent);
- touchEvent.recycle();
- }
-
- /**
- * Handles a hover enter event on a key.
- *
- * @param key The currently hovered key.
- */
- protected void onHoverEnterTo(final Key key) {
- if (DEBUG_HOVER) {
- Log.d(TAG, "onHoverEnterTo: key=" + key);
- }
- key.onPressed();
- mKeyboardView.invalidateKey(key);
- final KeyboardAccessibilityNodeProvider<KV> provider = getAccessibilityNodeProvider();
- provider.onHoverEnterTo(key);
- provider.performActionForKey(key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
- }
-
- /**
- * Handles a hover move event on a key.
- *
- * @param key The currently hovered key.
- */
- protected void onHoverMoveWithin(final Key key) { }
-
- /**
- * Handles a hover exit event on a key.
- *
- * @param key The currently hovered key.
- */
- protected void onHoverExitFrom(final Key key) {
- if (DEBUG_HOVER) {
- Log.d(TAG, "onHoverExitFrom: key=" + key);
- }
- key.onReleased();
- mKeyboardView.invalidateKey(key);
- final KeyboardAccessibilityNodeProvider<KV> provider = getAccessibilityNodeProvider();
- provider.onHoverExitFrom(key);
- }
-
- /**
- * Perform long click on a key.
- *
- * @param key A key to be long pressed on.
- */
- public void performLongClickOn(final Key key) {
- // A extended class should override this method to implement long press.
- }
-}
diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java
deleted file mode 100644
index cc244c305..000000000
--- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.accessibility;
-
-import android.graphics.Rect;
-import android.os.Bundle;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.accessibility.AccessibilityEventCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
-import androidx.core.view.accessibility.AccessibilityRecordCompat;
-import android.util.Log;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.inputmethod.EditorInfo;
-
-import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.latin.common.CoordinateUtils;
-import com.android.inputmethod.latin.settings.Settings;
-import com.android.inputmethod.latin.settings.SettingsValues;
-
-import java.util.List;
-
-/**
- * Exposes a virtual view sub-tree for {@link KeyboardView} and generates
- * {@link AccessibilityEvent}s for individual {@link Key}s.
- * <p>
- * A virtual sub-tree is composed of imaginary {@link View}s that are reported
- * as a part of the view hierarchy for accessibility purposes. This enables
- * custom views that draw complex content to report them selves as a tree of
- * virtual views, thus conveying their logical structure.
- * </p>
- */
-final class KeyboardAccessibilityNodeProvider<KV extends KeyboardView>
- extends AccessibilityNodeProviderCompat {
- private static final String TAG = KeyboardAccessibilityNodeProvider.class.getSimpleName();
-
- // From {@link android.view.accessibility.AccessibilityNodeInfo#UNDEFINED_ITEM_ID}.
- private static final int UNDEFINED = Integer.MAX_VALUE;
-
- private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper;
- private final AccessibilityUtils mAccessibilityUtils;
-
- /** Temporary rect used to calculate in-screen bounds. */
- private final Rect mTempBoundsInScreen = new Rect();
-
- /** The parent view's cached on-screen location. */
- private final int[] mParentLocation = CoordinateUtils.newInstance();
-
- /** The virtual view identifier for the focused node. */
- private int mAccessibilityFocusedView = UNDEFINED;
-
- /** The virtual view identifier for the hovering node. */
- private int mHoveringNodeId = UNDEFINED;
-
- /** The keyboard view to provide an accessibility node info. */
- private final KV mKeyboardView;
- /** The accessibility delegate. */
- private final KeyboardAccessibilityDelegate<KV> mDelegate;
-
- /** The current keyboard. */
- private Keyboard mKeyboard;
-
- public KeyboardAccessibilityNodeProvider(final KV keyboardView,
- final KeyboardAccessibilityDelegate<KV> delegate) {
- super();
- mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance();
- mAccessibilityUtils = AccessibilityUtils.getInstance();
- mKeyboardView = keyboardView;
- mDelegate = delegate;
-
- // Since this class is constructed lazily, we might not get a subsequent
- // call to setKeyboard() and therefore need to call it now.
- setKeyboard(keyboardView.getKeyboard());
- }
-
- /**
- * Sets the keyboard represented by this node provider.
- *
- * @param keyboard The keyboard that is being set to the keyboard view.
- */
- public void setKeyboard(final Keyboard keyboard) {
- mKeyboard = keyboard;
- }
-
- private Key getKeyOf(final int virtualViewId) {
- if (mKeyboard == null) {
- return null;
- }
- final List<Key> sortedKeys = mKeyboard.getSortedKeys();
- // Use a virtual view id as an index of the sorted keys list.
- if (virtualViewId >= 0 && virtualViewId < sortedKeys.size()) {
- return sortedKeys.get(virtualViewId);
- }
- return null;
- }
-
- private int getVirtualViewIdOf(final Key key) {
- if (mKeyboard == null) {
- return View.NO_ID;
- }
- final List<Key> sortedKeys = mKeyboard.getSortedKeys();
- final int size = sortedKeys.size();
- for (int index = 0; index < size; index++) {
- if (sortedKeys.get(index) == key) {
- // Use an index of the sorted keys list as a virtual view id.
- return index;
- }
- }
- return View.NO_ID;
- }
-
- /**
- * Creates and populates an {@link AccessibilityEvent} for the specified key
- * and event type.
- *
- * @param key A key on the host keyboard view.
- * @param eventType The event type to create.
- * @return A populated {@link AccessibilityEvent} for the key.
- * @see AccessibilityEvent
- */
- public AccessibilityEvent createAccessibilityEvent(final Key key, final int eventType) {
- final int virtualViewId = getVirtualViewIdOf(key);
- final String keyDescription = getKeyDescription(key);
- final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
- event.setPackageName(mKeyboardView.getContext().getPackageName());
- event.setClassName(key.getClass().getName());
- event.setContentDescription(keyDescription);
- event.setEnabled(true);
- final AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event);
- record.setSource(mKeyboardView, virtualViewId);
- return event;
- }
-
- public void onHoverEnterTo(final Key key) {
- final int id = getVirtualViewIdOf(key);
- if (id == View.NO_ID) {
- return;
- }
- // Start hovering on the key. Because our accessibility model is lift-to-type, we should
- // report the node info without click and long click actions to avoid unnecessary
- // announcements.
- mHoveringNodeId = id;
- // Invalidate the node info of the key.
- sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED);
- sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER);
- }
-
- public void onHoverExitFrom(final Key key) {
- mHoveringNodeId = UNDEFINED;
- // Invalidate the node info of the key to be able to revert the change we have done
- // in {@link #onHoverEnterTo(Key)}.
- sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED);
- sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT);
- }
-
- /**
- * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual
- * view, i.e. a descendant of the host View, with the given <code>virtualViewId</code> or
- * the host View itself if <code>virtualViewId</code> equals to {@link View#NO_ID}.
- * <p>
- * A virtual descendant is an imaginary View that is reported as a part of
- * the view hierarchy for accessibility purposes. This enables custom views
- * that draw complex content to report them selves as a tree of virtual
- * views, thus conveying their logical structure.
- * </p>
- * <p>
- * The implementer is responsible for obtaining an accessibility node info
- * from the pool of reusable instances and setting the desired properties of
- * the node info before returning it.
- * </p>
- *
- * @param virtualViewId A client defined virtual view id.
- * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual descendant or the host
- * View.
- * @see AccessibilityNodeInfoCompat
- */
- @Override
- public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(final int virtualViewId) {
- if (virtualViewId == UNDEFINED) {
- return null;
- }
- if (virtualViewId == View.NO_ID) {
- // We are requested to create an AccessibilityNodeInfo describing
- // this View, i.e. the root of the virtual sub-tree.
- final AccessibilityNodeInfoCompat rootInfo =
- AccessibilityNodeInfoCompat.obtain(mKeyboardView);
- ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);
- updateParentLocation();
-
- // Add the virtual children of the root View.
- final List<Key> sortedKeys = mKeyboard.getSortedKeys();
- final int size = sortedKeys.size();
- for (int index = 0; index < size; index++) {
- final Key key = sortedKeys.get(index);
- if (key.isSpacer()) {
- continue;
- }
- // Use an index of the sorted keys list as a virtual view id.
- rootInfo.addChild(mKeyboardView, index);
- }
- return rootInfo;
- }
-
- // Find the key that corresponds to the given virtual view id.
- final Key key = getKeyOf(virtualViewId);
- if (key == null) {
- Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
- return null;
- }
- final String keyDescription = getKeyDescription(key);
- final Rect boundsInParent = key.getHitBox();
-
- // Calculate the key's in-screen bounds.
- mTempBoundsInScreen.set(boundsInParent);
- mTempBoundsInScreen.offset(
- CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation));
- final Rect boundsInScreen = mTempBoundsInScreen;
-
- // Obtain and initialize an AccessibilityNodeInfo with information about the virtual view.
- final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
- info.setPackageName(mKeyboardView.getContext().getPackageName());
- // info.setTextEntryKey(true);
- info.setClassName(key.getClass().getName());
- info.setContentDescription(keyDescription);
- info.setBoundsInParent(boundsInParent);
- info.setBoundsInScreen(boundsInScreen);
- info.setParent(mKeyboardView);
- info.setSource(mKeyboardView, virtualViewId);
- info.setEnabled(key.isEnabled());
- info.setVisibleToUser(true);
- info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
- if (key.isLongPressEnabled()) {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK);
- }
-
- if (mAccessibilityFocusedView == virtualViewId) {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
- } else {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
- }
- return info;
- }
-
- @Override
- public boolean performAction(final int virtualViewId, final int action,
- final Bundle arguments) {
- final Key key = getKeyOf(virtualViewId);
- if (key == null) {
- return false;
- }
- return performActionForKey(key, action);
- }
-
- /**
- * Performs the specified accessibility action for the given key.
- *
- * @param key The on which to perform the action.
- * @param action The action to perform.
- * @return The result of performing the action, or false if the action is not supported.
- */
- boolean performActionForKey(final Key key, final int action) {
- switch (action) {
- case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
- mAccessibilityFocusedView = getVirtualViewIdOf(key);
- sendAccessibilityEventForKey(
- key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
- return true;
- case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
- mAccessibilityFocusedView = UNDEFINED;
- sendAccessibilityEventForKey(
- key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
- return true;
- case AccessibilityNodeInfoCompat.ACTION_CLICK:
- sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_CLICKED);
- mDelegate.performClickOn(key);
- return true;
- case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK:
- sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
- mDelegate.performLongClickOn(key);
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Sends an accessibility event for the given {@link Key}.
- *
- * @param key The key that's sending the event.
- * @param eventType The type of event to send.
- */
- void sendAccessibilityEventForKey(final Key key, final int eventType) {
- final AccessibilityEvent event = createAccessibilityEvent(key, eventType);
- mAccessibilityUtils.requestSendAccessibilityEvent(event);
- }
-
- /**
- * Returns the context-specific description for a {@link Key}.
- *
- * @param key The key to describe.
- * @return The context-specific description of the key.
- */
- private String getKeyDescription(final Key key) {
- final EditorInfo editorInfo = mKeyboard.mId.mEditorInfo;
- final boolean shouldObscure = mAccessibilityUtils.shouldObscureInput(editorInfo);
- final SettingsValues currentSettings = Settings.getInstance().getCurrent();
- final String keyCodeDescription = mKeyCodeDescriptionMapper.getDescriptionForKey(
- mKeyboardView.getContext(), mKeyboard, key, shouldObscure);
- if (currentSettings.isWordSeparator(key.getCode())) {
- return mAccessibilityUtils.getAutoCorrectionDescription(
- keyCodeDescription, shouldObscure);
- }
- return keyCodeDescription;
- }
-
- /**
- * Updates the parent's on-screen location.
- */
- private void updateParentLocation() {
- mKeyboardView.getLocationOnScreen(mParentLocation);
- }
-}
diff --git a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
deleted file mode 100644
index 3234993cf..000000000
--- a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * 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.graphics.Rect;
-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>
- 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();
-
- static {
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_DATE, R.string.keyboard_mode_date);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_DATETIME, R.string.keyboard_mode_date_time);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_EMAIL, R.string.keyboard_mode_email);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_IM, R.string.keyboard_mode_im);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_NUMBER, R.string.keyboard_mode_number);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_PHONE, R.string.keyboard_mode_phone);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_TEXT, R.string.keyboard_mode_text);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_TIME, R.string.keyboard_mode_time);
- KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_URL, R.string.keyboard_mode_url);
- }
-
- /** The most recently set keyboard mode. */
- private int mLastKeyboardMode = KEYBOARD_IS_HIDDEN;
- private static final int KEYBOARD_IS_HIDDEN = -1;
- // The rectangle region to ignore hover events.
- private final Rect mBoundsToIgnoreHoverEvent = new Rect();
-
-
- public MainKeyboardAccessibilityDelegate(final MainKeyboardView mainKeyboardView,
- final KeyDetector keyDetector) {
- super(mainKeyboardView, keyDetector);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setKeyboard(final Keyboard keyboard) {
- if (keyboard == null) {
- return;
- }
- final Keyboard lastKeyboard = getKeyboard();
- super.setKeyboard(keyboard);
- final int lastKeyboardMode = mLastKeyboardMode;
- mLastKeyboardMode = keyboard.mId.mMode;
-
- // Since this method is called even when accessibility is off, make sure
- // to check the state before announcing anything.
- if (!AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
- return;
- }
- // Announce the language name only when the language is changed.
- if (lastKeyboard == null || !keyboard.mId.mSubtype.equals(lastKeyboard.mId.mSubtype)) {
- announceKeyboardLanguage(keyboard);
- return;
- }
- // Announce the mode only when the mode is changed.
- if (keyboard.mId.mMode != lastKeyboardMode) {
- announceKeyboardMode(keyboard);
- return;
- }
- // Announce the keyboard type only when the type is changed.
- if (keyboard.mId.mElementId != lastKeyboard.mId.mElementId) {
- announceKeyboardType(keyboard, lastKeyboard);
- return;
- }
- }
-
- /**
- * Called when the keyboard is hidden and accessibility is enabled.
- */
- public void onHideWindow() {
- if (mLastKeyboardMode != KEYBOARD_IS_HIDDEN) {
- announceKeyboardHidden();
- }
- mLastKeyboardMode = KEYBOARD_IS_HIDDEN;
- }
-
- /**
- * Announces which language of keyboard is being displayed.
- *
- * @param keyboard The new keyboard.
- */
- private void announceKeyboardLanguage(final Keyboard keyboard) {
- final String languageText = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(
- keyboard.mId.mSubtype.getRawSubtype());
- sendWindowStateChanged(languageText);
- }
-
- /**
- * Announces which type of keyboard is being displayed.
- * If the keyboard type is unknown, no announcement is made.
- *
- * @param keyboard The new keyboard.
- */
- private void announceKeyboardMode(final Keyboard keyboard) {
- final Context context = mKeyboardView.getContext();
- final int modeTextResId = KEYBOARD_MODE_RES_IDS.get(keyboard.mId.mMode);
- if (modeTextResId == 0) {
- return;
- }
- final String modeText = context.getString(modeTextResId);
- final String text = context.getString(R.string.announce_keyboard_mode, modeText);
- sendWindowStateChanged(text);
- }
-
- /**
- * Announces which type of keyboard is being displayed.
- *
- * @param keyboard The new keyboard.
- * @param lastKeyboard The last keyboard.
- */
- private void announceKeyboardType(final Keyboard keyboard, final Keyboard lastKeyboard) {
- final int lastElementId = lastKeyboard.mId.mElementId;
- final int resId;
- switch (keyboard.mId.mElementId) {
- case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED:
- case KeyboardId.ELEMENT_ALPHABET:
- if (lastElementId == KeyboardId.ELEMENT_ALPHABET
- || lastElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
- // Transition between alphabet mode and automatic shifted mode should be silently
- // ignored because it can be determined by each key's talk back announce.
- return;
- }
- resId = R.string.spoken_description_mode_alpha;
- break;
- case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
- if (lastElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
- // Resetting automatic shifted mode by pressing the shift key causes the transition
- // from automatic shifted to manual shifted that should be silently ignored.
- return;
- }
- resId = R.string.spoken_description_shiftmode_on;
- break;
- case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
- if (lastElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED) {
- // Resetting caps locked mode by pressing the shift key causes the transition
- // from shift locked to shift lock shifted that should be silently ignored.
- return;
- }
- resId = R.string.spoken_description_shiftmode_locked;
- break;
- case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
- resId = R.string.spoken_description_shiftmode_locked;
- break;
- case KeyboardId.ELEMENT_SYMBOLS:
- resId = R.string.spoken_description_mode_symbol;
- break;
- case KeyboardId.ELEMENT_SYMBOLS_SHIFTED:
- resId = R.string.spoken_description_mode_symbol_shift;
- break;
- case KeyboardId.ELEMENT_PHONE:
- resId = R.string.spoken_description_mode_phone;
- break;
- case KeyboardId.ELEMENT_PHONE_SYMBOLS:
- resId = R.string.spoken_description_mode_phone_shift;
- break;
- default:
- return;
- }
- sendWindowStateChanged(resId);
- }
-
- /**
- * Announces that the keyboard has been hidden.
- */
- private void announceKeyboardHidden() {
- sendWindowStateChanged(R.string.announce_keyboard_hidden);
- }
-
- @Override
- public void performClickOn(final Key key) {
- final int x = key.getHitBox().centerX();
- final int y = key.getHitBox().centerY();
- if (DEBUG_HOVER) {
- Log.d(TAG, "performClickOn: key=" + key
- + " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y));
- }
- if (mBoundsToIgnoreHoverEvent.contains(x, y)) {
- // This hover exit event points to the key that should be ignored.
- // Clear the ignoring region to handle further hover events.
- mBoundsToIgnoreHoverEvent.setEmpty();
- return;
- }
- super.performClickOn(key);
- }
-
- @Override
- protected void onHoverEnterTo(final Key key) {
- final int x = key.getHitBox().centerX();
- final int y = key.getHitBox().centerY();
- if (DEBUG_HOVER) {
- Log.d(TAG, "onHoverEnterTo: key=" + key
- + " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y));
- }
- if (mBoundsToIgnoreHoverEvent.contains(x, y)) {
- return;
- }
- // This hover enter event points to the key that isn't in the ignoring region.
- // Further hover events should be handled.
- mBoundsToIgnoreHoverEvent.setEmpty();
- super.onHoverEnterTo(key);
- }
-
- @Override
- protected void onHoverExitFrom(final Key key) {
- final int x = key.getHitBox().centerX();
- final int y = key.getHitBox().centerY();
- if (DEBUG_HOVER) {
- Log.d(TAG, "onHoverExitFrom: key=" + key
- + " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y));
- }
- super.onHoverExitFrom(key);
- }
-
- @Override
- public void performLongClickOn(final Key key) {
- if (DEBUG_HOVER) {
- Log.d(TAG, "performLongClickOn: 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);
- downEvent.recycle();
- // Invoke {@link PointerTracker#onLongPressed()} as if a long press timeout has passed.
- tracker.onLongPressed();
- // 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.
- if (tracker.isInOperation()) {
- // This long press shows a more keys keyboard and further hover events should be
- // handled.
- mBoundsToIgnoreHoverEvent.setEmpty();
- return;
- }
- // This long press has handled at {@link MainKeyboardView#onLongPress(PointerTracker)}.
- // We should ignore further hover events on this key.
- mBoundsToIgnoreHoverEvent.set(key.getHitBox());
- if (key.hasNoPanelAutoMoreKey()) {
- // This long press has registered a code point without showing a more keys keyboard.
- // We should talk back the code point if possible.
- final int codePointOfNoPanelAutoMoreKey = key.getMoreKeys()[0].mCode;
- final String text = KeyCodeDescriptionMapper.getInstance().getDescriptionForCodePoint(
- mKeyboardView.getContext(), codePointOfNoPanelAutoMoreKey);
- if (text != null) {
- sendWindowStateChanged(text);
- }
- }
- }
-}
diff --git a/java/src/com/android/inputmethod/accessibility/MoreKeysKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MoreKeysKeyboardAccessibilityDelegate.java
deleted file mode 100644
index 4022da343..000000000
--- a/java/src/com/android/inputmethod/accessibility/MoreKeysKeyboardAccessibilityDelegate.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.keyboard.PointerTracker;
-
-/**
- * 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);
- }
-
- public void onDismissMoreKeysKeyboard() {
- sendWindowStateChanged(mCloseAnnounceResId);
- }
-
- @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);
- // TODO: Should fix this reference. This is a hack to clear the state of
- // {@link PointerTracker}.
- PointerTracker.dismissAllMoreKeysPanels();
- return;
- }
- // Close the more keys keyboard.
- // TODO: Should fix this reference. This is a hack to clear the state of
- // {@link PointerTracker}.
- PointerTracker.dismissAllMoreKeysPanels();
- }
-}