diff options
6 files changed, 103 insertions, 45 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java index dcebb1c04..1836f27b3 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java @@ -21,6 +21,7 @@ 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; @@ -31,6 +32,7 @@ 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.compat.SettingsSecureCompatUtils; import com.android.inputmethod.latin.R; public class AccessibilityUtils { @@ -113,13 +115,23 @@ public class AccessibilityUtils { } /** - * @return {@code true} if the device should not speak text (eg. - * non-control) characters + * 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; diff --git a/java/src/com/android/inputmethod/compat/SettingsSecureCompatUtils.java b/java/src/com/android/inputmethod/compat/SettingsSecureCompatUtils.java new file mode 100644 index 000000000..1b79992f0 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/SettingsSecureCompatUtils.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.compat; + +import java.lang.reflect.Field; + +public class SettingsSecureCompatUtils { + private static final Field FIELD_ACCESSIBILITY_SPEAK_PASSWORD = CompatUtils.getField( + android.provider.Settings.Secure.class, "ACCESSIBILITY_SPEAK_PASSWORD"); + + private SettingsSecureCompatUtils() { + // This class is non-instantiable. + } + + /** + * Whether to speak passwords while in accessibility mode. + */ + public static final String ACCESSIBILITY_SPEAK_PASSWORD = (String) CompatUtils.getFieldValue( + null, null, FIELD_ACCESSIBILITY_SPEAK_PASSWORD); +} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 840857778..ecc821a4b 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -16,6 +16,7 @@ package com.android.inputmethod.keyboard; +import android.text.TextUtils; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.EditorInfoCompatUtils; @@ -177,6 +178,14 @@ public class KeyboardId { ); } + public static boolean equivalentEditorInfoForKeyboard(EditorInfo a, EditorInfo b) { + if (a == null && b == null) return true; + if (a == null || b == null) return false; + return a.inputType == b.inputType + && a.imeOptions == b.imeOptions + && TextUtils.equals(a.privateImeOptions, b.privateImeOptions); + } + public static String modeName(int mode) { switch (mode) { case MODE_TEXT: return "text"; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 32aabf928..71a71d6fd 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -106,6 +106,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); + // TODO: Move this to KeyboardState. private class KeyboardLayoutState { private boolean mIsValid; private boolean mIsAlphabetMode; @@ -113,43 +114,36 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private boolean mIsShifted; public void save() { - if (mCurrentId == null) { - return; - } mIsAlphabetMode = isAlphabetMode(); if (mIsAlphabetMode) { mIsShiftLocked = mState.isShiftLocked(); mIsShifted = !mIsShiftLocked && mState.isShiftedOrShiftLocked(); } else { mIsShiftLocked = false; - mIsShifted = mCurrentId.equals(mSymbolsShiftedKeyboardId); + mIsShifted = isSymbolShifted(); } mIsValid = true; } - public KeyboardId getKeyboardId() { - if (!mIsValid) return mMainKeyboardId; - - if (mIsAlphabetMode) { - return mMainKeyboardId; + public void restore() { + mPrevMainKeyboardWasShiftLocked = false; + if (!mIsValid || mIsAlphabetMode) { + setAlphabetKeyboard(); } else { - return mIsShifted ? mSymbolsShiftedKeyboardId : mSymbolsKeyboardId; + if (mIsShifted) { + setSymbolsShiftedKeyboard(); + } else { + setSymbolsKeyboard(); + } } - } - public void restore() { if (!mIsValid) return; mIsValid = false; if (mIsAlphabetMode) { - final boolean isAlphabetMode = isAlphabetMode(); - final boolean isShiftLocked = isAlphabetMode && mState.isShiftLocked(); - final boolean isShifted = !isShiftLocked && mState.isShiftedOrShiftLocked(); - if (mIsShiftLocked != isShiftLocked) { - toggleCapsLock(); - } else if (mIsShifted != isShifted) { - onPressShift(false); - onReleaseShift(false); + setShiftLocked(mIsShiftLocked); + if (!mIsShiftLocked) { + setShifted(mIsShifted ? MANUAL_SHIFT : UNSHIFT); } } } @@ -205,8 +199,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues); mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues); mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues); + mState.onLoadKeyboard(); mLayoutSwitchBackSymbols = mResources.getString(R.string.layout_switch_back_symbols); - setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId())); mSavedKeyboardState.restore(); } catch (RuntimeException e) { Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e); @@ -215,7 +209,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } public void saveKeyboardState() { - mSavedKeyboardState.save(); + if (mCurrentId != null) { + mSavedKeyboardState.save(); + } } public void onFinishInputView() { @@ -382,6 +378,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } private void setShifted(int shiftMode) { + mInputMethodService.mHandler.cancelUpdateShiftState(); LatinKeyboard latinKeyboard = getLatinKeyboard(); if (latinKeyboard == null) return; @@ -405,19 +402,25 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } private void setShiftLocked(boolean shiftLocked) { + mInputMethodService.mHandler.cancelUpdateShiftState(); LatinKeyboard latinKeyboard = getLatinKeyboard(); if (latinKeyboard == null) return; mState.setShiftLocked(shiftLocked); latinKeyboard.setShiftLocked(shiftLocked); mKeyboardView.invalidateAllKeys(); + if (!shiftLocked) { + // To be able to turn off caps lock by "double tap" on shift key, we should ignore + // the second tap of the "double tap" from now for a while because we just have + // already turned off caps lock above. + mKeyboardView.startIgnoringDoubleTap(); + } } /** * Toggle keyboard shift state triggered by user touch event. */ public void toggleShift() { - mInputMethodService.mHandler.cancelUpdateShiftState(); if (DEBUG_STATE) { Log.d(TAG, "toggleShift: " + mState); } @@ -429,16 +432,16 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } public void toggleCapsLock() { - mInputMethodService.mHandler.cancelUpdateShiftState(); if (DEBUG_STATE) { Log.d(TAG, "toggleCapsLock: " + mState); } if (isAlphabetMode()) { if (mState.isShiftLocked()) { + setShiftLocked(false); + // TODO: Remove this. // Shift key is long pressed while caps lock state, we will toggle back to normal // state. And mark as if shift key is released. - setShiftLocked(false); - mState.onToggleCapsLock(); + mState.onReleaseCapsLock(); } else { setShiftLocked(true); } @@ -452,12 +455,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha toggleAlphabetAndSymbols(); } - private void startIgnoringDoubleTap() { - if (mKeyboardView != null) { - mKeyboardView.startIgnoringDoubleTap(); - } - } - /** * Update keyboard shift state triggered by connected EditText status change. */ @@ -505,7 +502,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha // shifted state. } else { // In base layout, chording or manual temporary upper case mode is started. - toggleShift(); + setShifted(MANUAL_SHIFT); } } else { // In symbol mode, just toggle symbol and symbol more keyboard. @@ -531,26 +528,22 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha if (isAlphabetMode) { if (mState.isShiftKeyMomentary()) { // After chording input while normal state. - toggleShift(); + setShifted(UNSHIFT); } else if (isShiftLocked && !isShiftLockShifted && (mState.isShiftKeyPressing() || mState.isShiftKeyPressingOnShifted()) && !withSliding) { // Shift has been long pressed, ignore this release. } else if (isShiftLocked && !mState.isShiftKeyIgnoring() && !withSliding) { // Shift has been pressed without chording while caps lock state. - toggleCapsLock(); - // To be able to turn off caps lock by "double tap" on shift key, we should ignore - // the second tap of the "double tap" from now for a while because we just have - // already turned off caps lock above. - startIgnoringDoubleTap(); + setShiftLocked(false); } else if (isShiftedOrShiftLocked && mState.isShiftKeyPressingOnShifted() && !withSliding) { // Shift has been pressed without chording while shifted state. - toggleShift(); + setShifted(UNSHIFT); } else if (isManualTemporaryUpperCaseFromAuto && mState.isShiftKeyPressing() && !withSliding) { // Shift has been pressed without chording while manual temporary upper case // transited from automatic temporary upper case. - toggleShift(); + setShifted(UNSHIFT); } } else { // In symbol mode, snap back to the previous keyboard mode if the user chords the shift @@ -601,6 +594,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } } + // TODO: Move this variable to KeyboardState. private boolean mPrevMainKeyboardWasShiftLocked; private void setSymbolsKeyboard() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index fd7e77863..e56159405 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -27,6 +27,13 @@ public class KeyboardState { public KeyboardState() { } + public void onLoadKeyboard() { + mKeyboardShiftState.setShifted(false); + mKeyboardShiftState.setShiftLocked(false); + mShiftKeyState.onRelease(); + mSymbolKeyState.onRelease(); + } + public boolean isShiftLocked() { return mKeyboardShiftState.isShiftLocked(); } @@ -91,7 +98,7 @@ public class KeyboardState { return mShiftKeyState.isPressingOnShifted(); } - public void onToggleCapsLock() { + public void onReleaseCapsLock() { mShiftKeyState.onRelease(); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5f446a5c4..c2656b891 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -62,6 +62,7 @@ import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.LatinKeyboard; @@ -442,7 +443,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public void onStartInputView(EditorInfo editorInfo, boolean restarting) { - if (hasMessages(MSG_PENDING_IMS_CALLBACK) && editorInfo == mAppliedEditorInfo) { + if (hasMessages(MSG_PENDING_IMS_CALLBACK) + && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { // Typically this is the second onStartInputView after orientation changed. resetPendingImsCallback(); } else { |