aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java45
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java27
-rw-r--r--java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java23
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java17
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestionsView.java10
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java4
6 files changed, 92 insertions, 34 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index 7e71b5f36..4a2542dec 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -19,15 +19,19 @@ package com.android.inputmethod.accessibility;
import android.content.Context;
import android.content.SharedPreferences;
import android.inputmethodservice.InputMethodService;
+import android.media.AudioManager;
import android.os.SystemClock;
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.AudioManagerCompatWrapper;
+import com.android.inputmethod.compat.InputTypeCompatUtils;
import com.android.inputmethod.compat.MotionEventCompatUtils;
+import com.android.inputmethod.latin.R;
public class AccessibilityUtils {
private static final String TAG = AccessibilityUtils.class.getSimpleName();
@@ -37,8 +41,10 @@ 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
@@ -67,9 +73,14 @@ public class AccessibilityUtils {
}
private void initInternal(Context context, SharedPreferences prefs) {
+ 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);
}
/**
@@ -102,6 +113,22 @@ public class AccessibilityUtils {
}
/**
+ * @return {@code true} if the device should not speak text (eg.
+ * non-control) characters
+ */
+ public boolean shouldObscureInput(EditorInfo attribute) {
+ if (attribute == null)
+ 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 InputTypeCompatUtils.isPasswordInputType(attribute.inputType);
+ }
+
+ /**
* Sends the specified text to the {@link AccessibilityManager} to be
* spoken.
*
@@ -117,7 +144,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);
@@ -127,4 +154,18 @@ public class AccessibilityUtils {
mAccessibilityManager.sendAccessibilityEvent(event);
}
+
+ /**
+ * Handles speaking the "connect a headset to hear passwords" notification
+ * when connecting to a password field.
+ *
+ * @param attribute The input connection's editor info attribute.
+ * @param restarting Whether the connection is being restarted.
+ */
+ public void onStartInputViewInternal(EditorInfo attribute, boolean restarting) {
+ if (shouldObscureInput(attribute)) {
+ final CharSequence text = mContext.getText(R.string.spoken_use_headphones);
+ speak(text);
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index e1b778126..4c109c708 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -21,7 +21,6 @@ import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Paint;
import android.inputmethodservice.InputMethodService;
-import android.media.AudioManager;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -29,8 +28,6 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.compat.AccessibilityEventCompatUtils;
-import com.android.inputmethod.compat.AudioManagerCompatWrapper;
-import com.android.inputmethod.compat.InputTypeCompatUtils;
import com.android.inputmethod.compat.MotionEventCompatUtils;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.KeyDetector;
@@ -48,7 +45,6 @@ public class AccessibleKeyboardViewProxy {
private FlickGestureDetector mGestureDetector;
private LatinKeyboardView mView;
private AccessibleKeyboardActionListener mListener;
- private AudioManagerCompatWrapper mAudioManager;
private int mScaledEdgeSlop;
private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY;
@@ -82,26 +78,6 @@ public class AccessibleKeyboardViewProxy {
mInputMethod = inputMethod;
mGestureDetector = new KeyboardFlickGestureDetector(inputMethod);
mScaledEdgeSlop = ViewConfiguration.get(inputMethod).getScaledEdgeSlop();
-
- final AudioManager audioManager = (AudioManager) inputMethod
- .getSystemService(Context.AUDIO_SERVICE);
- mAudioManager = new AudioManagerCompatWrapper(audioManager);
- }
-
- /**
- * @return {@code true} if the device should not speak text (eg. non-control) characters
- */
- private boolean shouldObscureInput() {
- // Always speak if the user is listening through headphones.
- if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn())
- return false;
-
- final EditorInfo info = mInputMethod.getCurrentInputEditorInfo();
- if (info == null)
- return false;
-
- // Don't speak if the IME is connected to a password field.
- return InputTypeCompatUtils.isPasswordInputType(info.inputType);
}
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event,
@@ -118,7 +94,8 @@ public class AccessibleKeyboardViewProxy {
if (key == null)
break;
- final boolean shouldObscure = shouldObscureInput();
+ final EditorInfo info = mInputMethod.getCurrentInputEditorInfo();
+ final boolean shouldObscure = AccessibilityUtils.getInstance().shouldObscureInput(info);
final CharSequence description = KeyCodeDescriptionMapper.getInstance()
.getDescriptionForKey(mView.getContext(), mView.getKeyboard(), key,
shouldObscure);
diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
index 5c54fa548..876bd65f6 100644
--- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
+++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
@@ -24,18 +24,22 @@ import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
+import android.util.Log;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Locale;
public class SuggestionSpanUtils {
+ private static final String TAG = SuggestionSpanUtils.class.getSimpleName();
// TODO: Use reflection to get field values
public static final String ACTION_SUGGESTION_PICKED =
"android.text.style.SUGGESTION_PICKED";
public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before";
public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode";
+ // TODO: Use the API constant after it gets public.
+ public static final int FLAG_AUTO_CORRECTION = 0x0004;
public static final int SUGGESTION_MAX_SIZE = 5;
public static final boolean SUGGESTION_SPAN_IS_SUPPORTED;
@@ -50,6 +54,25 @@ public class SuggestionSpanUtils {
CLASS_SuggestionSpan != null && CONSTRUCTOR_SuggestionSpan != null;
}
+ public static CharSequence getTextWithAutoCorrectionIndicatorUnderline(
+ Context context, CharSequence text) {
+ if (TextUtils.isEmpty(text) || CONSTRUCTOR_SuggestionSpan == null) {
+ return text;
+ }
+ final Spannable spannable = text instanceof Spannable
+ ? (Spannable) text : new SpannableString(text);
+ final Object[] args =
+ { context, null, new String[] {}, FLAG_AUTO_CORRECTION,
+ (Class<?>) SuggestionSpanPickedNotificationReceiver.class };
+ final Object ss = CompatUtils.newInstance(CONSTRUCTOR_SuggestionSpan, args);
+ if (ss == null) {
+ Log.w(TAG, "Suggestion span was not created.");
+ return text;
+ }
+ spannable.setSpan(ss, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return spannable;
+ }
+
public static CharSequence getTextWithSuggestionSpan(Context context,
CharSequence pickedWord, SuggestedWords suggestedWords) {
if (TextUtils.isEmpty(pickedWord) || CONSTRUCTOR_SuggestionSpan == null
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 3b311377b..958092bc7 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -693,6 +693,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
return;
}
+ // Forward this event to the accessibility utilities, if enabled.
+ final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance();
+ if (accessUtils.isTouchExplorationEnabled()) {
+ accessUtils.onStartInputViewInternal(attribute, restarting);
+ }
+
mSubtypeSwitcher.updateParametersOnStartInputView();
TextEntryState.reset();
@@ -1602,6 +1608,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mKeyboardSwitcher.onAutoCorrectionStateChanged(
words.hasWordAboveAutoCorrectionScoreThreshold());
}
+
+ // Put a blue underline to a word in TextView which will be auto-corrected.
+ final InputConnection ic = getCurrentInputConnection();
+ if (ic != null && Utils.willAutoCorrect(words)) {
+ final CharSequence textWithUnderline =
+ SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
+ this, mComposingStringBuilder);
+ if (!TextUtils.isEmpty(textWithUnderline)) {
+ ic.setComposingText(textWithUnderline, 1);
+ }
+ }
}
public void updateSuggestions() {
diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java
index fe54f4ae1..3271b8253 100644
--- a/java/src/com/android/inputmethod/latin/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java
@@ -260,7 +260,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
private CharSequence getStyledSuggestionWord(SuggestedWords suggestions, int pos) {
final CharSequence word = suggestions.getWord(pos);
- final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions);
+ final boolean isAutoCorrect = pos == 1 && Utils.willAutoCorrect(suggestions);
final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid;
if (!isAutoCorrect && !isTypedWordValid)
return word;
@@ -278,14 +278,10 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
return spannedWord;
}
- private static boolean willAutoCorrect(SuggestedWords suggestions) {
- return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion;
- }
-
private int getWordPosition(int index, SuggestedWords suggestions) {
// TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
// suggestions.
- final int centerPos = willAutoCorrect(suggestions) ? 1 : 0;
+ final int centerPos = Utils.willAutoCorrect(suggestions) ? 1 : 0;
if (index == mCenterSuggestionIndex) {
return centerPos;
} else if (index == centerPos) {
@@ -300,7 +296,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
final boolean isSuggested = (pos != 0);
final int color;
- if (index == mCenterSuggestionIndex && willAutoCorrect(suggestions)) {
+ if (index == mCenterSuggestionIndex && Utils.willAutoCorrect(suggestions)) {
color = mColorAutoCorrect;
} else if (isSuggested) {
color = mColorSuggested;
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 771276567..de2930460 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -790,4 +790,8 @@ public class Utils {
}
return -1;
}
+
+ public static boolean willAutoCorrect(SuggestedWords suggestions) {
+ return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion;
+ }
}