aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java96
1 files changed, 76 insertions, 20 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index ae614b7e0..616b1c6d7 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -16,19 +16,21 @@
package com.android.inputmethod.accessibility;
-import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
-import android.content.SharedPreferences;
import android.inputmethodservice.InputMethodService;
+import android.media.AudioManager;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.EditorInfo;
-import com.android.inputmethod.compat.AccessibilityEventCompatUtils;
-import com.android.inputmethod.compat.AccessibilityManagerCompatWrapper;
-import com.android.inputmethod.compat.MotionEventCompatUtils;
+import com.android.inputmethod.compat.AudioManagerCompatWrapper;
+import com.android.inputmethod.compat.SettingsSecureCompatUtils;
+import com.android.inputmethod.latin.InputTypeUtils;
+import com.android.inputmethod.latin.R;
public class AccessibilityUtils {
private static final String TAG = AccessibilityUtils.class.getSimpleName();
@@ -38,8 +40,9 @@ public class AccessibilityUtils {
private static final AccessibilityUtils sInstance = new AccessibilityUtils();
+ private Context mContext;
private AccessibilityManager mAccessibilityManager;
- private AccessibilityManagerCompatWrapper mCompatManager;
+ private AudioManagerCompatWrapper mAudioManager;
/*
* Setting this constant to {@code false} will disable all keyboard
@@ -48,15 +51,14 @@ public class AccessibilityUtils {
*/
private static final boolean ENABLE_ACCESSIBILITY = true;
- public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
+ public static void init(InputMethodService inputMethod) {
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);
+ sInstance.initInternal(inputMethod);
+ KeyCodeDescriptionMapper.init();
+ AccessibleKeyboardViewProxy.init(inputMethod);
}
public static AccessibilityUtils getInstance() {
@@ -67,10 +69,14 @@ public class AccessibilityUtils {
// This class is not publicly instantiable.
}
- private void initInternal(Context context, SharedPreferences prefs) {
+ private void initInternal(Context context) {
+ mContext = context;
mAccessibilityManager = (AccessibilityManager) context
.getSystemService(Context.ACCESSIBILITY_SERVICE);
- mCompatManager = new AccessibilityManagerCompatWrapper(mAccessibilityManager);
+
+ final AudioManager audioManager = (AudioManager) context
+ .getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager = new AudioManagerCompatWrapper(audioManager);
}
/**
@@ -82,10 +88,8 @@ public class AccessibilityUtils {
*/
public boolean isTouchExplorationEnabled() {
return ENABLE_ACCESSIBILITY
- && AccessibilityEventCompatUtils.supportsTouchExploration()
&& mAccessibilityManager.isEnabled()
- && !mCompatManager.getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
+ && mAccessibilityManager.isTouchExplorationEnabled();
}
/**
@@ -99,9 +103,35 @@ public class AccessibilityUtils {
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;
+ 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.
+ */
+ public boolean shouldObscureInput(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);
}
/**
@@ -120,7 +150,7 @@ public class AccessibilityUtils {
// 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);
+ .obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED);
event.setPackageName(PACKAGE);
event.setClassName(CLASS);
@@ -130,4 +160,30 @@ public class AccessibilityUtils {
mAccessibilityManager.sendAccessibilityEvent(event);
}
+
+ /**
+ * Handles speaking the "connect a headset to hear passwords" notification
+ * when connecting to a password field.
+ *
+ * @param editorInfo The input connection's editor info attribute.
+ * @param restarting Whether the connection is being restarted.
+ */
+ public void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) {
+ if (shouldObscureInput(editorInfo)) {
+ final CharSequence text = mContext.getText(R.string.spoken_use_headphones);
+ speak(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(AccessibilityEvent event) {
+ if (mAccessibilityManager.isEnabled()) {
+ mAccessibilityManager.sendAccessibilityEvent(event);
+ }
+ }
}