diff options
Diffstat (limited to 'java/src')
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; + } } |