From c2ee72a214fef46bc02ce486220365bbefd78714 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Thu, 7 Mar 2013 10:39:55 -0800 Subject: [PATCH] Announce keyboard mode changes as a WINDOW_STATE_CHANGED event. Bug: 8165295 Change-Id: Ie416f6cdb68377f3e06f30e9b6363c38ba2a602d --- java/res/values/strings.xml | 23 +++++ .../accessibility/AccessibilityUtils.java | 17 +++- .../AccessibleKeyboardViewProxy.java | 86 ++++++++++++++++++- .../android/inputmethod/latin/LatinIME.java | 4 + 4 files changed, 124 insertions(+), 6 deletions(-) diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 68fa8fd37..e89174b02 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -223,6 +223,29 @@ Phone symbols mode + + Keyboard hidden + + Showing %s keyboard + + date + + date and time + + email + + messaging + + number + + phone + + text + + time + + URL + Voice input key diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java index bf1cea9c3..ee52de1d1 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java @@ -79,17 +79,25 @@ public final class AccessibilityUtils { 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 a spoken feedback service is turned on. + * and system accessibility is turned on. * * @return {@code true} if touch exploration is enabled. */ public boolean isTouchExplorationEnabled() { - return ENABLE_ACCESSIBILITY - && mAccessibilityManager.isEnabled() - && mAccessibilityManager.isTouchExplorationEnabled(); + return isAccessibilityEnabled() && mAccessibilityManager.isTouchExplorationEnabled(); } /** @@ -113,6 +121,7 @@ public final class AccessibilityUtils { * * @return {@code true} if the device should obscure password characters. */ + @SuppressWarnings("deprecation") public boolean shouldObscureInput(final EditorInfo editorInfo) { if (editorInfo == null) return false; diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index d05fd9eb5..e6b44120f 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -22,8 +22,11 @@ import android.support.v4.view.AccessibilityDelegateCompat; import android.support.v4.view.ViewCompat; import android.support.v4.view.accessibility.AccessibilityEventCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.util.SparseIntArray; 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.Keyboard; @@ -35,6 +38,21 @@ import com.android.inputmethod.latin.R; public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat { private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy(); + /** 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); + } + private InputMethodService mInputMethod; private MainKeyboardView mView; private AccessibilityEntityProvider mAccessibilityNodeProvider; @@ -85,11 +103,75 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp mAccessibilityNodeProvider.setView(view); } + /** + * Called when the keyboard layout changes. + *

+ * Note: This method will be called even if accessibility is not + * enabled. + */ public void setKeyboard() { - if (mAccessibilityNodeProvider == null) { + if (mAccessibilityNodeProvider != null) { + mAccessibilityNodeProvider.setKeyboard(); + } + + // Since this method is called even when accessibility is off, make sure + // to check the state before announcing anything. + if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) { + announceKeyboardMode(); + } + } + + /** + * Called when the keyboard is hidden and accessibility is enabled. + */ + public void onHideWindow() { + announceKeyboardHidden(); + } + + /** + * Announces which type of keyboard is being displayed. If the keyboard type + * is unknown, no announcement is made. + */ + private void announceKeyboardMode() { + final Keyboard keyboard = mView.getKeyboard(); + final int resId = KEYBOARD_MODE_RES_IDS.get(keyboard.mId.mMode); + if (resId == 0) { return; } - mAccessibilityNodeProvider.setKeyboard(); + + final Context context = mView.getContext(); + final String keyboardMode = context.getString(resId); + final String text = context.getString(R.string.announce_keyboard_mode, keyboardMode); + + sendWindowStateChanged(text); + } + + /** + * Announces that the keyboard has been hidden. + */ + private void announceKeyboardHidden() { + final Context context = mView.getContext(); + final String text = context.getString(R.string.announce_keyboard_hidden); + + sendWindowStateChanged(text); + } + + /** + * Sends a window state change event with the specified text. + * + * @param text + */ + private void sendWindowStateChanged(final String text) { + final AccessibilityEvent stateChange = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + mView.onInitializeAccessibilityEvent(stateChange); + stateChange.getText().add(text); + stateChange.setContentDescription(null); + + final ViewParent parent = mView.getParent(); + if (parent != null) { + parent.requestSendAccessibilityEvent(mView, stateChange); + } } /** diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index e9347461c..bb7e2d1c2 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -955,6 +955,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction LatinImeLogger.commit(); mKeyboardSwitcher.onHideWindow(); + if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) { + AccessibleKeyboardViewProxy.getInstance().onHideWindow(); + } + if (TRACE) Debug.stopMethodTracing(); if (mOptionsDialog != null && mOptionsDialog.isShowing()) { mOptionsDialog.dismiss();