Announce keyboard mode changes as a WINDOW_STATE_CHANGED event.
Bug: 8165295
Change-Id: Ie416f6cdb68377f3e06f30e9b6363c38ba2a602d
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 68fa8fd..e89174b 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -223,6 +223,29 @@
<!-- Spoken feedback after changing to the shifted phone dialer (symbols) keyboard. -->
<string name="spoken_description_mode_phone_shift">Phone symbols mode</string>
+ <!-- Spoken feedback when the keyboard is hidden. -->
+ <string name="announce_keyboard_hidden">Keyboard hidden</string>
+ <!-- Spoken feedback when the keyboard mode changes. -->
+ <string name="announce_keyboard_mode">Showing <xliff:g id="mode" example="email">%s</xliff:g> keyboard</string>
+ <!-- Description of the keyboard mode for entering dates. -->
+ <string name="keyboard_mode_date">date</string>
+ <!-- Description of the keyboard mode for entering dates and times. -->
+ <string name="keyboard_mode_date_time">date and time</string>
+ <!-- Description of the keyboard mode for entering email addresses. -->
+ <string name="keyboard_mode_email">email</string>
+ <!-- Description of the keyboard mode for entering text messages. -->
+ <string name="keyboard_mode_im">messaging</string>
+ <!-- Description of the keyboard mode for entering numbers. -->
+ <string name="keyboard_mode_number">number</string>
+ <!-- Description of the keyboard mode for entering phone numbers. -->
+ <string name="keyboard_mode_phone">phone</string>
+ <!-- Description of the keyboard mode for entering generic text. -->
+ <string name="keyboard_mode_text">text</string>
+ <!-- Description of the keyboard mode for entering times. -->
+ <string name="keyboard_mode_time">time</string>
+ <!-- Description of the keyboard mode for entering URLs. -->
+ <string name="keyboard_mode_url">URL</string>
+
<!-- Preferences item for enabling speech input -->
<string name="voice_input">Voice input key</string>
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index bf1cea9..ee52de1 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -80,16 +80,24 @@
}
/**
+ * 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 @@
*
* @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 d05fd9e..e6b4412 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.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 @@
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 @@
mAccessibilityNodeProvider.setView(view);
}
+ /**
+ * Called when the keyboard layout changes.
+ * <p>
+ * <b>Note:</b> 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 e934746..bb7e2d1 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -955,6 +955,10 @@
LatinImeLogger.commit();
mKeyboardSwitcher.onHideWindow();
+ if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
+ AccessibleKeyboardViewProxy.getInstance().onHideWindow();
+ }
+
if (TRACE) Debug.stopMethodTracing();
if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
mOptionsDialog.dismiss();