diff options
Diffstat (limited to 'java/src')
19 files changed, 330 insertions, 669 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java index d834dd10b..961176bb8 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java @@ -19,28 +19,13 @@ package com.android.inputmethod.accessibility; import android.content.Context; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; -import android.os.Looper; -import android.os.Message; import android.os.Vibrator; -import android.text.TextUtils; import android.view.KeyEvent; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; - -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.StaticInnerHandlerWrapper; public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActionListener { private static final AccessibleInputMethodServiceProxy sInstance = new AccessibleInputMethodServiceProxy(); - /* - * Delay for the handler event that's fired when Accessibility is on and the - * user hovers outside of any valid keys. This is used to let the user know - * that if they lift their finger, nothing will be typed. - */ - private static final long DELAY_NO_HOVER_SELECTION = 250; - /** * Duration of the key click vibration in milliseconds. */ @@ -51,35 +36,6 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi private InputMethodService mInputMethod; private Vibrator mVibrator; private AudioManager mAudioManager; - private AccessibilityHandler mAccessibilityHandler; - - private static class AccessibilityHandler - extends StaticInnerHandlerWrapper<AccessibleInputMethodServiceProxy> { - private static final int MSG_NO_HOVER_SELECTION = 0; - - public AccessibilityHandler(AccessibleInputMethodServiceProxy outerInstance, - Looper looper) { - super(outerInstance, looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_NO_HOVER_SELECTION: - getOuterInstance().notifyNoHoverSelection(); - break; - } - } - - public void postNoHoverSelection() { - removeMessages(MSG_NO_HOVER_SELECTION); - sendEmptyMessageDelayed(MSG_NO_HOVER_SELECTION, DELAY_NO_HOVER_SELECTION); - } - - public void cancelNoHoverSelection() { - removeMessages(MSG_NO_HOVER_SELECTION); - } - } public static void init(InputMethodService inputMethod) { sInstance.initInternal(inputMethod); @@ -97,26 +53,6 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi mInputMethod = inputMethod; mVibrator = (Vibrator) inputMethod.getSystemService(Context.VIBRATOR_SERVICE); mAudioManager = (AudioManager) inputMethod.getSystemService(Context.AUDIO_SERVICE); - mAccessibilityHandler = new AccessibilityHandler(this, inputMethod.getMainLooper()); - } - - /** - * If touch exploration is enabled, cancels the event sent by - * {@link AccessibleInputMethodServiceProxy#onHoverExit(int)} because the - * user is currently hovering above a key. - */ - @Override - public void onHoverEnter(int primaryCode) { - mAccessibilityHandler.cancelNoHoverSelection(); - } - - /** - * If touch exploration is enabled, sends a delayed event to notify the user - * that they are not currently hovering above a key. - */ - @Override - public void onHoverExit(int primaryCode) { - mAccessibilityHandler.postNoHoverSelection(); } /** @@ -145,27 +81,4 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi mAudioManager.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, FX_VOLUME); mInputMethod.sendDownUpKeyEvents(keyCode); } - - /** - * When Accessibility is turned on, notifies the user that they are not - * currently hovering above a key. By default this will speak the currently - * entered text. - */ - private void notifyNoHoverSelection() { - final ExtractedText extracted = mInputMethod.getCurrentInputConnection().getExtractedText( - new ExtractedTextRequest(), 0); - - if (extracted == null) - return; - - final CharSequence text; - - if (TextUtils.isEmpty(extracted.text)) { - text = mInputMethod.getString(R.string.spoken_no_text_entered); - } else { - text = mInputMethod.getString(R.string.spoken_current_text_is, extracted.text); - } - - AccessibilityUtils.getInstance().speak(text); - } } diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java index c1e92bec8..31d17d09f 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java @@ -18,24 +18,6 @@ package com.android.inputmethod.accessibility; public interface AccessibleKeyboardActionListener { /** - * Called when the user hovers inside a key. This is sent only when - * Accessibility is turned on. For keys that repeat, this is only called - * once. - * - * @param primaryCode the code of the key that was hovered over - */ - public void onHoverEnter(int primaryCode); - - /** - * Called when the user hovers outside a key. This is sent only when - * Accessibility is turned on. For keys that repeat, this is only called - * once. - * - * @param primaryCode the code of the key that was hovered over - */ - public void onHoverExit(int primaryCode); - - /** * @param direction the direction of the flick gesture, one of * <ul> * <li>{@link FlickGestureDetector#FLICK_UP} diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index 9141daaee..f98359dc1 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -156,10 +156,8 @@ public class AccessibleKeyboardViewProxy { return; if (entering) { - mListener.onHoverEnter(key.mCode); mView.sendAccessibilityEvent(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER); } else { - mListener.onHoverExit(key.mCode); mView.sendAccessibilityEvent(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_EXIT); } } diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index efaf58fc2..3b4149d7f 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -176,25 +176,6 @@ public class KeyCodeDescriptionMapper { } /** - * Returns the keycode for the specified key given the current keyboard - * state. - * - * @param keyboard The keyboard on which the key resides. - * @param key The key from which to obtain a key code. - * @return the key code for the specified key - */ - private int getCorrectKeyCode(Keyboard keyboard, Key key) { - // If keyboard is in manual temporary upper case state and key has - // manual temporary uppercase letter as key hint letter, alternate - // character code should be sent. - if (keyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter() - && !TextUtils.isEmpty(key.mHintLabel)) { - return key.mHintLabel.charAt(0); - } - return key.mCode; - } - - /** * Returns a localized character sequence describing what will happen when * the specified key is pressed based on its key code. * <p> @@ -217,7 +198,7 @@ public class KeyCodeDescriptionMapper { */ private CharSequence getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key, boolean shouldObscure) { - final int code = getCorrectKeyCode(keyboard, key); + final int code = key.mCode; if (keyboard.isShiftLocked() && mShiftLockedKeyCodeMap.containsKey(code)) { return context.getString(mShiftLockedKeyCodeMap.get(code)); diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java index a013ebca9..f632b0e02 100644 --- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java +++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java @@ -16,23 +16,6 @@ package com.android.inputmethod.deprecated; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; -import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; -import com.android.inputmethod.compat.SharedPreferencesCompat; -import com.android.inputmethod.deprecated.voice.FieldContext; -import com.android.inputmethod.deprecated.voice.Hints; -import com.android.inputmethod.deprecated.voice.SettingsUtil; -import com.android.inputmethod.deprecated.voice.VoiceInput; -import com.android.inputmethod.keyboard.KeyboardSwitcher; -import com.android.inputmethod.latin.EditingUtils; -import com.android.inputmethod.latin.LatinIME; -import com.android.inputmethod.latin.LatinIME.UIHandler; -import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.SuggestedWords; -import com.android.inputmethod.latin.Utils; - import android.app.AlertDialog; import android.content.ContentResolver; import android.content.Context; @@ -63,6 +46,24 @@ import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.widget.TextView; +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; +import com.android.inputmethod.compat.SharedPreferencesCompat; +import com.android.inputmethod.deprecated.voice.FieldContext; +import com.android.inputmethod.deprecated.voice.Hints; +import com.android.inputmethod.deprecated.voice.SettingsUtil; +import com.android.inputmethod.deprecated.voice.VoiceInput; +import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.LatinKeyboardView; +import com.android.inputmethod.latin.EditingUtils; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.LatinIME.UIHandler; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.SubtypeSwitcher; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.Utils; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -747,8 +748,9 @@ public class VoiceProxy implements VoiceInput.UiListener { // keep showing the warning. if (mSubtypeSwitcher.isVoiceMode() && windowToken != null) { // Close keyboard view if it is been shown. - if (KeyboardSwitcher.getInstance().isInputViewShown()) - KeyboardSwitcher.getInstance().getKeyboardView().purgeKeyboardAndClosing(); + final LatinKeyboardView keyboardView = KeyboardSwitcher.getInstance().getKeyboardView(); + if (keyboardView != null && keyboardView.isShown()) + keyboardView.purgeKeyboardAndClosing(); startListening(false, windowToken); } // If we have no token, onAttachedToWindow will take care of showing dialog and start diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index a2d379643..d4419aeaf 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -66,14 +66,13 @@ public class Key { private static final int LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO = 0x80; private static final int LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO = 0x100; private static final int LABEL_FLAGS_HAS_POPUP_HINT = 0x200; - private static final int LABEL_FLAGS_HAS_UPPERCASE_LETTER = 0x400; + private static final int LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT = 0x400; private static final int LABEL_FLAGS_HAS_HINT_LABEL = 0x800; private static final int LABEL_FLAGS_WITH_ICON_LEFT = 0x1000; private static final int LABEL_FLAGS_WITH_ICON_RIGHT = 0x2000; private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000; private static final int LABEL_FLAGS_PRESERVE_CASE = 0x8000; - private static final int LABEL_FLAGS_INACTIVATED_LABEL = 0x10000; - private static final int LABEL_FLAGS_INACTIVATED_UPPERCASE_LETTER = 0x20000; + private static final int LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED = 0x10000; /** Icon to display instead of a label. Icon takes precedence over a label */ private final int mIconAttrId; @@ -114,7 +113,8 @@ public class Key { public static final int BACKGROUND_TYPE_NORMAL = 0; public static final int BACKGROUND_TYPE_FUNCTIONAL = 1; public static final int BACKGROUND_TYPE_ACTION = 2; - public static final int BACKGROUND_TYPE_STICKY = 3; + public static final int BACKGROUND_TYPE_STICKY_OFF = 3; + public static final int BACKGROUND_TYPE_STICKY_ON = 4; private final int mActionFlags; private static final int ACTION_FLAGS_IS_REPEATABLE = 0x01; @@ -125,8 +125,6 @@ public class Key { /** The current pressed state of this key */ private boolean mPressed; - /** If this is a sticky key, is its highlight on? */ - private boolean mHighlightOn; /** Key is enabled and responds on press */ private boolean mEnabled = true; @@ -303,31 +301,46 @@ public class Key { keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId); mHintLabel = adjustCaseOfStringForKeyboardId(style.getString( keyAttr, R.styleable.Keyboard_Key_keyHintLabel), preserveCase, params.mId); - mOutputText = adjustCaseOfStringForKeyboardId(style.getString( + String outputText = adjustCaseOfStringForKeyboardId(style.getString( keyAttr, R.styleable.Keyboard_Key_keyOutputText), preserveCase, params.mId); - // Choose the first letter of the label as primary code if not - // specified. - final int code = adjustCaseOfCodeForKeyboardId(style.getInt( - keyAttr, R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED), preserveCase, - params.mId); - if (code == Keyboard.CODE_UNSPECIFIED && mOutputText == null + final int code = style.getInt( + keyAttr, R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED); + // Choose the first letter of the label as primary code if not specified. + if (code == Keyboard.CODE_UNSPECIFIED && TextUtils.isEmpty(outputText) && !TextUtils.isEmpty(mLabel)) { - if (mLabel.length() != 1) { - Log.w(TAG, "Label is not a single letter: label=" + mLabel); + if (mLabel.codePointCount(0, mLabel.length()) == 1) { + final int activatedCode; + // Use the first letter of the hint label if shiftedLetterActivated flag is + // specified. + if (hasShiftedLetterHint() && isShiftedLetterActivated() + && !TextUtils.isEmpty(mHintLabel)) { + activatedCode = mHintLabel.codePointAt(0); + } else { + activatedCode = mLabel.codePointAt(0); + } + mCode = getRtlParenthesisCode(activatedCode, params.mIsRtlKeyboard); + } else { + // In some locale and case, the character might be represented by multiple code + // points, such as upper case Eszett of German alphabet. + outputText = mLabel; + mCode = Keyboard.CODE_OUTPUT_TEXT; } - final int firstChar = mLabel.charAt(0); - mCode = getRtlParenthesisCode(firstChar, params.mIsRtlKeyboard); - } else if (code == Keyboard.CODE_UNSPECIFIED && mOutputText != null) { + } else if (code == Keyboard.CODE_UNSPECIFIED && outputText != null) { mCode = Keyboard.CODE_OUTPUT_TEXT; } else { - mCode = code; + mCode = adjustCaseOfCodeForKeyboardId(code, preserveCase, params.mId); } + mOutputText = outputText; mAltCode = adjustCaseOfCodeForKeyboardId(style.getInt(keyAttr, R.styleable.Keyboard_Key_altCode, Keyboard.CODE_UNSPECIFIED), preserveCase, params.mId); mHashCode = hashCode(this); keyAttr.recycle(); + + if (hasShiftedLetterHint() && TextUtils.isEmpty(mHintLabel)) { + Log.w(TAG, "hasShiftedLetterHint specified without keyHintLabel: " + this); + } } private static int adjustCaseOfCodeForKeyboardId(int code, boolean preserveCase, @@ -335,7 +348,8 @@ public class Key { if (!Keyboard.isLetterCode(code) || preserveCase) return code; final String text = new String(new int[] { code } , 0, 1); final String casedText = adjustCaseOfStringForKeyboardId(text, preserveCase, id); - return casedText.codePointAt(0); + return casedText.codePointCount(0, casedText.length()) == 1 + ? casedText.codePointAt(0) : Keyboard.CODE_UNSPECIFIED; } private static String adjustCaseOfStringForKeyboardId(String text, boolean preserveCase, @@ -362,6 +376,7 @@ public class Key { key.mLabel, key.mHintLabel, key.mIconAttrId, + key.mBackgroundType, // Key can be distinguishable without the following members. // key.mAltCode, // key.mOutputText, @@ -370,7 +385,6 @@ public class Key { // key.mIcon, // key.mDisabledIconAttrId, // key.mPreviewIconAttrId, - // key.mBackgroundType, // key.mHorizontalGap, // key.mVerticalGap, // key.mVisualInsetLeft, @@ -388,7 +402,9 @@ public class Key { && o.mHeight == mHeight && o.mCode == mCode && TextUtils.equals(o.mLabel, mLabel) - && TextUtils.equals(o.mHintLabel, mHintLabel); + && TextUtils.equals(o.mHintLabel, mHintLabel) + && o.mIconAttrId != mIconAttrId + && o.mBackgroundType != mBackgroundType; } @Override @@ -401,6 +417,15 @@ public class Key { return o instanceof Key && equals((Key)o); } + @Override + public String toString() { + String top = Keyboard.printableCode(mCode); + if (mLabel != null && mLabel.length() != 1) { + top += "/\"" + mLabel + '"'; + } + return String.format("%s %d,%d", top, mX, mY); + } + public void markAsLeftEdge(Keyboard.Params params) { mHitBox.left = params.mHorizontalEdgesPadding; } @@ -417,10 +442,6 @@ public class Key { mHitBox.bottom = params.mOccupiedHeight + params.mBottomPadding; } - public boolean isSticky() { - return mBackgroundType == BACKGROUND_TYPE_STICKY; - } - public boolean isSpacer() { return false; } @@ -486,8 +507,8 @@ public class Key { return (mLabelFlags & LABEL_FLAGS_HAS_POPUP_HINT) != 0; } - public boolean hasUppercaseLetter() { - return (mLabelFlags & LABEL_FLAGS_HAS_UPPERCASE_LETTER) != 0; + public boolean hasShiftedLetterHint() { + return (mLabelFlags & LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT) != 0; } public boolean hasHintLabel() { @@ -506,12 +527,8 @@ public class Key { return (mLabelFlags & LABEL_FLAGS_AUTO_X_SCALE) != 0; } - public boolean isInactivatedLabel() { - return (mLabelFlags & LABEL_FLAGS_INACTIVATED_LABEL) != 0; - } - - public boolean isInactivatedUppercaseLetter() { - return (mLabelFlags & LABEL_FLAGS_INACTIVATED_UPPERCASE_LETTER) != 0; + public boolean isShiftedLetterActivated() { + return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0; } // TODO: Get rid of this method. @@ -542,10 +559,6 @@ public class Key { mPressed = false; } - public void setHighlightOn(boolean highlightOn) { - mHighlightOn = highlightOn; - } - public boolean isEnabled() { return mEnabled; } @@ -639,21 +652,17 @@ public class Key { * @see android.graphics.drawable.StateListDrawable#setState(int[]) */ public int[] getCurrentDrawableState() { - final boolean pressed = mPressed; - switch (mBackgroundType) { case BACKGROUND_TYPE_FUNCTIONAL: - return pressed ? KEY_STATE_FUNCTIONAL_PRESSED : KEY_STATE_FUNCTIONAL_NORMAL; + return mPressed ? KEY_STATE_FUNCTIONAL_PRESSED : KEY_STATE_FUNCTIONAL_NORMAL; case BACKGROUND_TYPE_ACTION: - return pressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL; - case BACKGROUND_TYPE_STICKY: - if (mHighlightOn) { - return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON; - } else { - return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF; - } + return mPressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL; + case BACKGROUND_TYPE_STICKY_OFF: + return mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF; + case BACKGROUND_TYPE_STICKY_ON: + return mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON; default: /* BACKGROUND_TYPE_NORMAL */ - return pressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; + return mPressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; } } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index dd882098d..8832d8fd1 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -31,7 +30,6 @@ import android.view.InflateException; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.keyboard.internal.KeyStyles; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; -import com.android.inputmethod.keyboard.internal.KeyboardShiftState; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.XmlParseUtils; @@ -130,16 +128,12 @@ public class Keyboard { /** List of keys and icons in this keyboard */ public final Set<Key> mKeys; public final Set<Key> mShiftKeys; - public final Set<Key> mShiftLockKeys; public final KeyboardIconsSet mIconsSet; private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); private final ProximityInfo mProximityInfo; - // TODO: Remove this variable. - private final KeyboardShiftState mShiftState = new KeyboardShiftState(); - public Keyboard(Params params) { mId = params.mId; mThemeId = params.mThemeId; @@ -156,7 +150,6 @@ public class Keyboard { mKeys = Collections.unmodifiableSet(params.mKeys); mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys); - mShiftLockKeys = Collections.unmodifiableSet(params.mShiftLockKeys); mIconsSet = params.mIconsSet; mProximityInfo = new ProximityInfo( @@ -188,70 +181,18 @@ public class Keyboard { } // TODO: Remove this method. - boolean hasShiftLockKey() { - return !mShiftLockKeys.isEmpty(); - } - - // TODO: Remove this method. - void setShiftLocked(boolean newShiftLockState) { - for (final Key key : mShiftLockKeys) { - // To represent "shift locked" state. The highlight is handled by background image that - // might be a StateListDrawable. - key.setHighlightOn(newShiftLockState); - final int attrId = newShiftLockState - ? R.styleable.Keyboard_iconShiftKeyShifted - : R.styleable.Keyboard_iconShiftKey; - key.setIcon(mIconsSet.getIconByAttrId(attrId)); - } - mShiftState.setShiftLocked(newShiftLockState); - } - - // TODO: Move this method to KeyboardId. public boolean isShiftLocked() { - return mShiftState.isShiftLocked(); - } - - private void setShiftKeyGraphics(boolean newShiftState) { - if (mShiftState.isShiftLocked()) { - return; - } - for (final Key key : mShiftKeys) { - final int attrId = newShiftState - ? R.styleable.Keyboard_iconShiftKeyShifted - : R.styleable.Keyboard_iconShiftKey; - key.setIcon(mIconsSet.getIconByAttrId(attrId)); - } + return mId.isAlphabetShiftLockedKeyboard(); } // TODO: Remove this method. - void setShifted(boolean newShiftState) { - setShiftKeyGraphics(newShiftState); - mShiftState.setShifted(newShiftState); - } - - // TODO: Move this method to KeyboardId. public boolean isShiftedOrShiftLocked() { - return mShiftState.isShiftedOrShiftLocked(); - } - - // TODO: Remove this method - void setAutomaticTemporaryUpperCase() { - setShiftKeyGraphics(true); - mShiftState.setAutomaticTemporaryUpperCase(); - } - - // TODO: Move this method to KeyboardId. - public boolean isManualTemporaryUpperCase() { - return mShiftState.isManualTemporaryUpperCase(); + return mId.isAlphabetShiftedOrShiftLockedKeyboard(); } // TODO: Remove this method. - public String adjustLabelCase(String label) { - if (mId.isAlphabetKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) - && label.length() < 3 && Character.isLowerCase(label.charAt(0))) { - return label.toUpperCase(mId.mLocale); - } - return label; + public boolean isManualShifted() { + return mId.isAlphabetManualShiftedKeyboard(); } public static boolean isLetterCode(int code) { @@ -291,7 +232,6 @@ public class Keyboard { public final Set<Key> mKeys = new HashSet<Key>(); public final Set<Key> mShiftKeys = new HashSet<Key>(); - public final Set<Key> mShiftLockKeys = new HashSet<Key>(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); public KeyboardSet.KeysCache mKeysCache; @@ -360,7 +300,6 @@ public class Keyboard { protected void clearKeys() { mKeys.clear(); mShiftKeys.clear(); - mShiftLockKeys.clear(); clearHistogram(); } @@ -370,9 +309,6 @@ public class Keyboard { updateHistogram(key); if (key.mCode == Keyboard.CODE_SHIFT) { mShiftKeys.add(key); - if (key.isSticky()) { - mShiftLockKeys.add(key); - } } } @@ -437,6 +373,8 @@ public class Keyboard { case CODE_DELETE: return "delete"; case CODE_SHORTCUT: return "shortcut"; case CODE_UNSPECIFIED: return "unspec"; + case CODE_TAB: return "tab"; + case CODE_ENTER: return "enter"; default: if (code <= 0) Log.w(TAG, "Unknown non-positive key code=" + code); if (code < CODE_SPACE) return String.format("'\\u%02x'", code); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 8db8c9460..997b952de 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -124,6 +124,22 @@ public class KeyboardId { return mElementId < ELEMENT_SYMBOLS; } + // This should be aligned with {@link KeyboardShiftState#isShiftLocked}. + public boolean isAlphabetShiftLockedKeyboard() { + return mElementId == ELEMENT_ALPHABET_SHIFT_LOCKED + || mElementId == ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED; + } + + // This should be aligned with {@link KeyboardShiftState#isShiftedOrShiftLocked}. + public boolean isAlphabetShiftedOrShiftLockedKeyboard() { + return isAlphabetKeyboard() && mElementId != ELEMENT_ALPHABET; + } + + // This should be aligned with {@link KeyboardShiftState#isManualShifted}. + public boolean isAlphabetManualShiftedKeyboard() { + return mElementId != ELEMENT_ALPHABET_MANUAL_SHIFTED; + } + public boolean isSymbolsKeyboard() { return mElementId == ELEMENT_SYMBOLS || mElementId == ELEMENT_SYMBOLS_SHIFTED; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index ae5e4e860..d35948bad 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -59,6 +59,14 @@ public class KeyboardSet { private final Params mParams; private final KeysCache mKeysCache = new KeysCache(); + public static class KeyboardSetException extends RuntimeException { + public final KeyboardId mKeyboardId; + public KeyboardSetException(Throwable cause, KeyboardId keyboardId) { + super(cause); + mKeyboardId = keyboardId; + } + } + public static class KeysCache { private final Map<Key, Key> mMap; @@ -77,17 +85,6 @@ public class KeyboardSet { } } - static class KeyboardElement { - final int mElementId; - final int mLayoutId; - final boolean mAutoGenerate; - KeyboardElement(int elementId, int layoutId, boolean autoGenerate) { - mElementId = elementId; - mLayoutId = layoutId; - mAutoGenerate = autoGenerate; - } - } - static class Params { int mMode; int mInputType; @@ -100,8 +97,9 @@ public class KeyboardSet { Locale mLocale; int mOrientation; int mWidth; - final Map<Integer, KeyboardElement> mElementKeyboards = - new HashMap<Integer, KeyboardElement>(); + // KeyboardSet element id to keyboard layout XML id map. + final Map<Integer, Integer> mKeyboardSetElementIdToXmlIdMap = + new HashMap<Integer, Integer>(); Params() {} } @@ -117,41 +115,36 @@ public class KeyboardSet { mParams = params; } - public Keyboard getMainKeyboard() { - return getKeyboard(false, false, false); - } - - public Keyboard getSymbolsKeyboard() { - return getKeyboard(true, false, false); - } - - public Keyboard getSymbolsShiftedKeyboard() { - final Keyboard keyboard = getKeyboard(true, false, true); - // TODO: Remove this logic once we introduce initial keyboard shift state attribute. - // Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a. - // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked() - // that takes care of the current keyboard having such shift key or not. - keyboard.setShiftLocked(keyboard.hasShiftLockKey()); - return keyboard; - } - - private Keyboard getKeyboard(boolean isSymbols, boolean isShiftLock, boolean isShift) { - final int elementId = KeyboardSet.getElementId( - mParams.mMode, isSymbols, isShiftLock, isShift); - final KeyboardElement keyboardElement = mParams.mElementKeyboards.get(elementId); - // TODO: If keyboardElement.mAutoGenerate is true, the keyboard will be auto generated - // based on keyboardElement.mKayoutId Keyboard XML definition. - final KeyboardId id = KeyboardSet.getKeyboardId(elementId, isSymbols, mParams); - final Keyboard keyboard = getKeyboard(mContext, keyboardElement, id); - return keyboard; - } + public Keyboard getKeyboard(int baseKeyboardSetElementId) { + final int keyboardSetElementId; + switch (mParams.mMode) { + case KeyboardId.MODE_PHONE: + keyboardSetElementId = + (baseKeyboardSetElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED) + ? KeyboardId.ELEMENT_PHONE_SHIFTED : KeyboardId.ELEMENT_PHONE; + break; + case KeyboardId.MODE_NUMBER: + keyboardSetElementId = KeyboardId.ELEMENT_NUMBER; + break; + default: + keyboardSetElementId = baseKeyboardSetElementId; + break; + } - public KeyboardId getMainKeyboardId() { - final int elementId = KeyboardSet.getElementId(mParams.mMode, false, false, false); - return KeyboardSet.getKeyboardId(elementId, false, mParams); + Integer keyboardXmlId = mParams.mKeyboardSetElementIdToXmlIdMap.get(keyboardSetElementId); + if (keyboardXmlId == null) { + keyboardXmlId = mParams.mKeyboardSetElementIdToXmlIdMap.get( + KeyboardId.ELEMENT_ALPHABET); + } + final KeyboardId id = getKeyboardId(keyboardSetElementId); + try { + return getKeyboard(mContext, keyboardXmlId, id); + } catch (RuntimeException e) { + throw new KeyboardSetException(e, id); + } } - private Keyboard getKeyboard(Context context, KeyboardElement element, KeyboardId id) { + private Keyboard getKeyboard(Context context, int keyboardXmlId, KeyboardId id) { final Resources res = context.getResources(); final SoftReference<Keyboard> ref = sKeyboardCache.get(id); Keyboard keyboard = (ref == null) ? null : ref.get(); @@ -160,10 +153,10 @@ public class KeyboardSet { try { final Keyboard.Builder<Keyboard.Params> builder = new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params()); - if (element.mAutoGenerate) { + if (id.isAlphabetKeyboard()) { builder.setAutoGenerate(mKeysCache); } - builder.load(element.mLayoutId, id); + builder.load(keyboardXmlId, id); builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled); keyboard = builder.build(); } finally { @@ -179,36 +172,22 @@ public class KeyboardSet { Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": HIT id=" + id); } - // TODO: Remove setShiftLocked and setShift calls. - keyboard.setShiftLocked(false); - keyboard.setShifted(false); return keyboard; } - private static int getElementId(int mode, boolean isSymbols, boolean isShiftLock, - boolean isShift) { - switch (mode) { - case KeyboardId.MODE_PHONE: - return (isSymbols && isShift) - ? KeyboardId.ELEMENT_PHONE_SHIFTED : KeyboardId.ELEMENT_PHONE; - case KeyboardId.MODE_NUMBER: - return KeyboardId.ELEMENT_NUMBER; - default: - if (isSymbols) { - return isShift - ? KeyboardId.ELEMENT_SYMBOLS_SHIFTED : KeyboardId.ELEMENT_SYMBOLS; - } - // TODO: Consult isShiftLock and isShift to determine the element. - return KeyboardId.ELEMENT_ALPHABET; - } - } - - private static KeyboardId getKeyboardId(int elementId, boolean isSymbols, Params params) { + // Note: The keyboard for each locale, shift state, and mode are represented as KeyboardSet + // element id that is a key in keyboard_set.xml. Also that file specifies which XML layout + // should be used for each keyboard. The KeyboardId is an internal key for Keyboard object. + private KeyboardId getKeyboardId(int keyboardSetElementId) { + final Params params = mParams; + final boolean isSymbols = (keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS + || keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED); final boolean hasShortcutKey = params.mVoiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain); - return new KeyboardId(elementId, params.mLocale, params.mOrientation, params.mWidth, - params.mMode, params.mInputType, params.mImeOptions, params.mSettingsKeyEnabled, - params.mNoSettingsKey, params.mVoiceKeyEnabled, hasShortcutKey); + return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation, + params.mWidth, params.mMode, params.mInputType, params.mImeOptions, + params.mSettingsKeyEnabled, params.mNoSettingsKey, params.mVoiceKeyEnabled, + hasShortcutKey); } public static class Builder { @@ -345,10 +324,7 @@ public class KeyboardSet { R.styleable.KeyboardSet_Element_elementName, 0); final int elementKeyboard = a.getResourceId( R.styleable.KeyboardSet_Element_elementKeyboard, 0); - final boolean elementAutoGenerate = a.getBoolean( - R.styleable.KeyboardSet_Element_elementAutoGenerate, false); - mParams.mElementKeyboards.put(elementName, new KeyboardElement( - elementName, elementKeyboard, elementAutoGenerate)); + mParams.mKeyboardSetElementIdToXmlIdMap.put(elementName, elementKeyboard); } finally { a.recycle(); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 5a59cc1c7..951bcdbfd 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -27,6 +27,8 @@ import android.view.View; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; +import com.android.inputmethod.keyboard.KeyboardSet.KeyboardSetException; +import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.keyboard.internal.KeyboardState; import com.android.inputmethod.latin.DebugSettings; import com.android.inputmethod.latin.InputView; @@ -135,24 +137,17 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, settingsValues.isVoiceKeyEnabled(editorInfo), settingsValues.isVoiceKeyOnMain()); mKeyboardSet = builder.build(); - final KeyboardId mainKeyboardId = mKeyboardSet.getMainKeyboardId(); try { mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols)); - } catch (RuntimeException e) { - Log.w(TAG, "loading keyboard failed: " + mainKeyboardId, e); - LatinImeLogger.logOnException(mainKeyboardId.toString(), e); + } catch (KeyboardSetException e) { + Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); + LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause()); return; } - // TODO: Should get rid of this special case handling for Phone Number layouts once we - // have separate layouts with unique KeyboardIds for alphabet and alphabet-shifted - // respectively. - if (mainKeyboardId.isPhoneKeyboard()) { - mState.setSymbolsKeyboard(); - } } public void saveKeyboardState() { - if (isKeyboardAvailable()) { + if (getKeyboard() != null) { mState.onSaveKeyboardState(); } } @@ -184,31 +179,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged); } - public boolean isAlphabetMode() { - final Keyboard keyboard = getKeyboard(); - return keyboard != null && keyboard.mId.isAlphabetKeyboard(); - } - - public boolean isInputViewShown() { - return mCurrentInputView != null && mCurrentInputView.isShown(); - } - - public boolean isShiftedOrShiftLocked() { - final Keyboard keyboard = getKeyboard(); - return keyboard != null && keyboard.isShiftedOrShiftLocked(); - } - - public boolean isManualTemporaryUpperCase() { - final Keyboard keyboard = getKeyboard(); - return keyboard != null && keyboard.isManualTemporaryUpperCase(); - } - - public boolean isKeyboardAvailable() { - if (mKeyboardView != null) - return mKeyboardView.getKeyboard() != null; - return false; - } - public Keyboard getKeyboard() { if (mKeyboardView != null) { return mKeyboardView.getKeyboard(); @@ -235,91 +205,46 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, mState.onCancelInput(isSinglePointer()); } - // TODO: Remove these constants. - private static final int ALPHABET_UNSHIFTED = 0; - private static final int ALPHABET_MANUAL_SHIFTED = 1; - private static final int ALPHABET_AUTOMATIC_SHIFTED = 2; - private static final int ALPHABET_SHIFT_LOCKED = 3; - private static final int ALPHABET_SHIFT_LOCK_SHIFTED = 4; - - // TODO: Remove this method. - private void updateAlphabetKeyboardShiftState(int shiftMode) { - mInputMethodService.mHandler.cancelUpdateShiftState(); - Keyboard keyboard = getKeyboard(); - if (keyboard == null) - return; - switch (shiftMode) { - case ALPHABET_UNSHIFTED: - keyboard.setShifted(false); - break; - case ALPHABET_MANUAL_SHIFTED: - keyboard.setShifted(true); - break; - case ALPHABET_AUTOMATIC_SHIFTED: - keyboard.setAutomaticTemporaryUpperCase(); - break; - case ALPHABET_SHIFT_LOCKED: - keyboard.setShiftLocked(true); - break; - case ALPHABET_SHIFT_LOCK_SHIFTED: - keyboard.setShiftLocked(true); - keyboard.setShifted(true); - break; - } - mKeyboardView.invalidateAllKeys(); - if (shiftMode != ALPHABET_SHIFT_LOCKED) { - // 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(); - } - } - // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetKeyboard() { - setKeyboard(mKeyboardSet.getMainKeyboard()); - updateAlphabetKeyboardShiftState(ALPHABET_UNSHIFTED); + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetManualShiftedKeyboard() { - setKeyboard(mKeyboardSet.getMainKeyboard()); - updateAlphabetKeyboardShiftState(ALPHABET_MANUAL_SHIFTED); + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetAutomaticShiftedKeyboard() { - setKeyboard(mKeyboardSet.getMainKeyboard()); - updateAlphabetKeyboardShiftState(ALPHABET_AUTOMATIC_SHIFTED); + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetShiftLockedKeyboard() { - setKeyboard(mKeyboardSet.getMainKeyboard()); - updateAlphabetKeyboardShiftState(ALPHABET_SHIFT_LOCKED); + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setAlphabetShiftLockShiftedKeyboard() { - setKeyboard(mKeyboardSet.getMainKeyboard()); - updateAlphabetKeyboardShiftState(ALPHABET_SHIFT_LOCK_SHIFTED); + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setSymbolsKeyboard() { - setKeyboard(mKeyboardSet.getSymbolsKeyboard()); + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS)); } // Implements {@link KeyboardState.SwitchActions}. @Override public void setSymbolsShiftedKeyboard() { - setKeyboard(mKeyboardSet.getSymbolsShiftedKeyboard()); + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); } // Implements {@link KeyboardState.SwitchActions}. @@ -328,6 +253,24 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState()); } + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void startDoubleTapTimer() { + final LatinKeyboardView keyboardView = getKeyboardView(); + if (keyboardView != null) { + final TimerProxy timer = keyboardView.getTimerProxy(); + timer.startDoubleTapTimer(); + } + } + + // Implements {@link KeyboardState.SwitchActions}. + @Override + public boolean isInDoubleTapTimeout() { + final LatinKeyboardView keyboardView = getKeyboardView(); + return (keyboardView != null) + ? keyboardView.getTimerProxy().isInDoubleTapTimeout() : false; + } + public boolean isInMomentarySwitchState() { return mState.isInMomentarySwitchState(); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index d977327a8..2cbd132ca 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -53,12 +53,12 @@ import java.util.HashMap; * @attr ref R.styleable#KeyboardView_keyLargeLetterRatio * @attr ref R.styleable#KeyboardView_keyLabelRatio * @attr ref R.styleable#KeyboardView_keyHintLetterRatio - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterRatio + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintRatio * @attr ref R.styleable#KeyboardView_keyHintLabelRatio * @attr ref R.styleable#KeyboardView_keyLabelHorizontalPadding * @attr ref R.styleable#KeyboardView_keyHintLetterPadding * @attr ref R.styleable#KeyboardView_keyPopupHintLetterPadding - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterPadding + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintPadding * @attr ref R.styleable#KeyboardView_keyTextStyle * @attr ref R.styleable#KeyboardView_keyPreviewLayout * @attr ref R.styleable#KeyboardView_keyPreviewTextRatio @@ -68,8 +68,8 @@ import java.util.HashMap; * @attr ref R.styleable#KeyboardView_keyTextColorDisabled * @attr ref R.styleable#KeyboardView_keyHintLetterColor * @attr ref R.styleable#KeyboardView_keyHintLabelColor - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterInactivatedColor - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterActivatedColor + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintInactivatedColor + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintActivatedColor * @attr ref R.styleable#KeyboardView_shadowColor * @attr ref R.styleable#KeyboardView_shadowRadius */ @@ -175,20 +175,20 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public final float mKeyLabelHorizontalPadding; public final float mKeyHintLetterPadding; public final float mKeyPopupHintLetterPadding; - public final float mKeyUppercaseLetterPadding; + public final float mKeyShiftedLetterHintPadding; public final int mShadowColor; public final float mShadowRadius; public final Drawable mKeyBackground; public final int mKeyHintLetterColor; public final int mKeyHintLabelColor; - public final int mKeyUppercaseLetterInactivatedColor; - public final int mKeyUppercaseLetterActivatedColor; + public final int mKeyShiftedLetterHintInactivatedColor; + public final int mKeyShiftedLetterHintActivatedColor; private final float mKeyLetterRatio; private final float mKeyLargeLetterRatio; private final float mKeyLabelRatio; private final float mKeyHintLetterRatio; - private final float mKeyUppercaseLetterRatio; + private final float mKeyShiftedLetterHintRatio; private final float mKeyHintLabelRatio; private static final float UNDEFINED_RATIO = -1.0f; @@ -197,7 +197,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public int mKeyLargeLetterSize; public int mKeyLabelSize; public int mKeyHintLetterSize; - public int mKeyUppercaseLetterSize; + public int mKeyShiftedLetterHintSize; public int mKeyHintLabelSize; public KeyDrawParams(TypedArray a) { @@ -216,8 +216,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } mKeyLargeLetterRatio = getRatio(a, R.styleable.KeyboardView_keyLargeLetterRatio); mKeyHintLetterRatio = getRatio(a, R.styleable.KeyboardView_keyHintLetterRatio); - mKeyUppercaseLetterRatio = getRatio(a, - R.styleable.KeyboardView_keyUppercaseLetterRatio); + mKeyShiftedLetterHintRatio = getRatio(a, + R.styleable.KeyboardView_keyShiftedLetterHintRatio); mKeyHintLabelRatio = getRatio(a, R.styleable.KeyboardView_keyHintLabelRatio); mKeyLabelHorizontalPadding = a.getDimension( R.styleable.KeyboardView_keyLabelHorizontalPadding, 0); @@ -225,17 +225,17 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { R.styleable.KeyboardView_keyHintLetterPadding, 0); mKeyPopupHintLetterPadding = a.getDimension( R.styleable.KeyboardView_keyPopupHintLetterPadding, 0); - mKeyUppercaseLetterPadding = a.getDimension( - R.styleable.KeyboardView_keyUppercaseLetterPadding, 0); + mKeyShiftedLetterHintPadding = a.getDimension( + R.styleable.KeyboardView_keyShiftedLetterHintPadding, 0); mKeyTextColor = a.getColor(R.styleable.KeyboardView_keyTextColor, 0xFF000000); mKeyTextInactivatedColor = a.getColor( R.styleable.KeyboardView_keyTextInactivatedColor, 0xFF000000); mKeyHintLetterColor = a.getColor(R.styleable.KeyboardView_keyHintLetterColor, 0); mKeyHintLabelColor = a.getColor(R.styleable.KeyboardView_keyHintLabelColor, 0); - mKeyUppercaseLetterInactivatedColor = a.getColor( - R.styleable.KeyboardView_keyUppercaseLetterInactivatedColor, 0); - mKeyUppercaseLetterActivatedColor = a.getColor( - R.styleable.KeyboardView_keyUppercaseLetterActivatedColor, 0); + mKeyShiftedLetterHintInactivatedColor = a.getColor( + R.styleable.KeyboardView_keyShiftedLetterHintInactivatedColor, 0); + mKeyShiftedLetterHintActivatedColor = a.getColor( + R.styleable.KeyboardView_keyShiftedLetterHintActivatedColor, 0); mKeyTextStyle = Typeface.defaultFromStyle( a.getInt(R.styleable.KeyboardView_keyTextStyle, Typeface.NORMAL)); mShadowColor = a.getColor(R.styleable.KeyboardView_shadowColor, 0); @@ -251,7 +251,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mKeyLabelSize = (int)(keyHeight * mKeyLabelRatio); mKeyLargeLetterSize = (int)(keyHeight * mKeyLargeLetterRatio); mKeyHintLetterSize = (int)(keyHeight * mKeyHintLetterRatio); - mKeyUppercaseLetterSize = (int)(keyHeight * mKeyUppercaseLetterRatio); + mKeyShiftedLetterHintSize = (int)(keyHeight * mKeyShiftedLetterHintRatio); mKeyHintLabelSize = (int)(keyHeight * mKeyHintLabelRatio); } } @@ -527,8 +527,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final Drawable icon = key.getIcon(mKeyboard.mIconsSet); float positionX = centerX; if (key.mLabel != null) { - // Switch the character to uppercase if shift is pressed - final String label = mKeyboard.adjustLabelCase(key.mLabel); + final String label = key.mLabel; // For characters, use large font. For labels like "Done", use smaller font. paint.setTypeface(key.selectTypeface(params.mKeyTextStyle)); final int labelSize = key.selectTextSize(params.mKeyLetterSize, @@ -571,14 +570,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { Math.min(1.0f, (keyWidth * MAX_LABEL_RATIO) / getLabelWidth(label, paint))); } - // TODO: Remove this first if-clause. - if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { - paint.setColor(params.mKeyTextInactivatedColor); - } else if (key.isInactivatedLabel()) { - paint.setColor(params.mKeyTextInactivatedColor); - } else { - paint.setColor(params.mKeyTextColor); - } + paint.setColor(key.isShiftedLetterActivated() + ? params.mKeyTextInactivatedColor : params.mKeyTextColor); if (key.isEnabled()) { // Set a drop shadow for the text paint.setShadowLayer(params.mShadowRadius, 0, 0, params.mShadowColor); @@ -620,16 +613,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { hintColor = params.mKeyHintLabelColor; hintSize = params.mKeyHintLabelSize; paint.setTypeface(Typeface.DEFAULT); - } else if (key.hasUppercaseLetter()) { - // TODO: Remove this first if-clause. - if (mKeyboard.isManualTemporaryUpperCase()) { - hintColor = params.mKeyUppercaseLetterActivatedColor; - } else if (!key.isInactivatedUppercaseLetter()) { - hintColor = params.mKeyUppercaseLetterActivatedColor; - } else { - hintColor = params.mKeyUppercaseLetterInactivatedColor; - } - hintSize = params.mKeyUppercaseLetterSize; + } else if (key.hasShiftedLetterHint()) { + hintColor = key.isShiftedLetterActivated() + ? params.mKeyShiftedLetterHintActivatedColor + : params.mKeyShiftedLetterHintInactivatedColor; + hintSize = params.mKeyShiftedLetterHintSize; } else { // key.hasHintLetter() hintColor = params.mKeyHintLetterColor; hintSize = params.mKeyHintLetterSize; @@ -644,9 +632,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { hintX = positionX + getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) * 2; hintY = centerY + getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint) / 2; paint.setTextAlign(Align.LEFT); - } else if (key.hasUppercaseLetter()) { + } else if (key.hasShiftedLetterHint()) { // The hint label is placed at top-right corner of the key. Used mainly on tablet. - hintX = keyWidth - params.mKeyUppercaseLetterPadding + hintX = keyWidth - params.mKeyShiftedLetterHintPadding - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2; hintY = -paint.ascent(); paint.setTextAlign(Align.CENTER); @@ -870,7 +858,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mPreviewTextSize); previewText.setTypeface(params.mKeyTextStyle); } - previewText.setText(mKeyboard.adjustLabelCase(key.mLabel)); + previewText.setText(key.mLabel); } else { final Drawable previewIcon = mKeyboard.mIconsSet.getIconByAttrId( key.mPreviewIconAttrId); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 7e8a7180c..5aad67d49 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -29,7 +29,6 @@ import android.os.Message; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; -import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -64,8 +63,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke SuddenJumpingTouchEventHandler.ProcessMotionEvent { private static final String TAG = LatinKeyboardView.class.getSimpleName(); - private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true; - // TODO: Kill process when the usability study mode was changed. private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; @@ -111,16 +108,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private int mOldPointerCount = 1; private Key mOldKey; - // To detect double tap. - protected GestureDetector mGestureDetector; - private final KeyTimerHandler mKeyTimerHandler; private static class KeyTimerHandler extends StaticInnerHandlerWrapper<LatinKeyboardView> implements TimerProxy { private static final int MSG_REPEAT_KEY = 1; private static final int MSG_LONGPRESS_KEY = 2; - private static final int MSG_IGNORE_DOUBLE_TAP = 3; + private static final int MSG_DOUBLE_TAP = 3; private static final int MSG_KEY_TYPED = 4; private final int mKeyRepeatInterval; @@ -184,70 +178,24 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } @Override - public void cancelKeyTimers() { - cancelKeyRepeatTimer(); - cancelLongPressTimer(); - removeMessages(MSG_IGNORE_DOUBLE_TAP); - } - - public void startIgnoringDoubleTap() { - sendMessageDelayed(obtainMessage(MSG_IGNORE_DOUBLE_TAP), + public void startDoubleTapTimer() { + sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP), ViewConfiguration.getDoubleTapTimeout()); } - public boolean isIgnoringDoubleTap() { - return hasMessages(MSG_IGNORE_DOUBLE_TAP); - } - - public void cancelAllMessages() { - cancelKeyTimers(); + @Override + public boolean isInDoubleTapTimeout() { + return hasMessages(MSG_DOUBLE_TAP); } - } - - class DoubleTapListener extends GestureDetector.SimpleOnGestureListener { - private boolean mProcessingShiftDoubleTapEvent = false; @Override - public boolean onDoubleTap(MotionEvent firstDown) { - final Keyboard keyboard = getKeyboard(); - if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard.mId.isAlphabetKeyboard()) { - final int pointerIndex = firstDown.getActionIndex(); - final int id = firstDown.getPointerId(pointerIndex); - final PointerTracker tracker = PointerTracker.getPointerTracker( - id, LatinKeyboardView.this); - final Key key = tracker.getKeyOn((int)firstDown.getX(), (int)firstDown.getY()); - // If the first down event is on shift key. - if (key != null && key.isShift()) { - mProcessingShiftDoubleTapEvent = true; - return true; - } - } - mProcessingShiftDoubleTapEvent = false; - return false; + public void cancelKeyTimers() { + cancelKeyRepeatTimer(); + cancelLongPressTimer(); } - @Override - public boolean onDoubleTapEvent(MotionEvent secondTap) { - if (mProcessingShiftDoubleTapEvent - && secondTap.getAction() == MotionEvent.ACTION_DOWN) { - final MotionEvent secondDown = secondTap; - final int pointerIndex = secondDown.getActionIndex(); - final int id = secondDown.getPointerId(pointerIndex); - final PointerTracker tracker = PointerTracker.getPointerTracker( - id, LatinKeyboardView.this); - final Key key = tracker.getKeyOn((int)secondDown.getX(), (int)secondDown.getY()); - // If the second down event is also on shift key. - if (key != null && key.isShift()) { - // Detected a double tap on shift key. If we are in the ignoring double tap - // mode, it means we have already turned off caps lock in - // {@link KeyboardSwitcher#onReleaseShift} . - onDoubleTapShiftKey(mKeyTimerHandler.isIgnoringDoubleTap()); - return true; - } - // Otherwise these events should not be handled as double tap. - mProcessingShiftDoubleTapEvent = false; - } - return mProcessingShiftDoubleTapEvent; + public void cancelAllMessages() { + cancelKeyTimers(); } } @@ -303,11 +251,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this); - final boolean ignoreMultitouch = true; - mGestureDetector = new GestureDetector( - getContext(), new DoubleTapListener(), null, ignoreMultitouch); - mGestureDetector.setIsLongpressEnabled(false); - mHasDistinctMultitouch = context.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); @@ -342,11 +285,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke PointerTracker.setParameters(mPointerTrackerParams); } - public void startIgnoringDoubleTap() { - if (ENABLE_CAPSLOCK_BY_DOUBLETAP) - mKeyTimerHandler.startIgnoringDoubleTap(); - } - public void setKeyboardActionListener(KeyboardActionListener listener) { mKeyboardActionListener = listener; PointerTracker.setKeyboardActionListener(listener); @@ -451,17 +389,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke return onLongPress(parentKey, tracker); } - private void onDoubleTapShiftKey(final boolean ignore) { - // When shift key is double tapped, the first tap is correctly processed as usual tap. And - // the second tap is treated as this double tap event, so that we need not mark tracker - // calling setAlreadyProcessed() nor remove the tracker from mPointerQueue. - if (ignore) { - invokeCustomRequest(LatinIME.CODE_HAPTIC_AND_AUDIO_FEEDBACK); - } else { - invokeCodeInput(Keyboard.CODE_CAPSLOCK); - } - } - // This default implementation returns a more keys panel. protected MoreKeysPanel onCreateMoreKeysPanel(Key parentKey) { if (parentKey.mMoreKeys == null) @@ -548,7 +475,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mMoreKeysPanelPointerTrackerId = tracker.mPointerId; final Keyboard keyboard = getKeyboard(); - moreKeysPanel.setShifted(keyboard.isShiftedOrShiftLocked()); final int pointX = (mConfigShowMiniKeyboardAtTouchedPoint) ? tracker.getLastX() : parentKey.mX + parentKey.mWidth / 2; final int pointY = parentKey.mY - keyboard.mVerticalGap; @@ -596,14 +522,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke return true; } - // Gesture detector must be enabled only when mini-keyboard is not on the screen. - if (mMoreKeysPanel == null && mGestureDetector != null - && mGestureDetector.onTouchEvent(me)) { - PointerTracker.dismissAllKeyPreviews(); - mKeyTimerHandler.cancelKeyTimers(); - return true; - } - final long eventTime = me.getEventTime(); final int index = me.getActionIndex(); final int id = me.getPointerId(index); diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java index 1f9ed5e91..72d5b6889 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java @@ -131,13 +131,6 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { } @Override - public void setShifted(boolean shifted) { - final Keyboard keyboard = getKeyboard(); - keyboard.setShifted(shifted); - invalidateAllKeys(); - } - - @Override public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, PopupWindow window, KeyboardActionListener listener) { mController = controller; diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java index a3ff37269..f9a196d24 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java @@ -24,9 +24,6 @@ public interface MoreKeysPanel extends PointerTracker.KeyEventHandler { public boolean dismissMoreKeysPanel(); } - // TODO: Remove this method. - public void setShifted(boolean shifted); - /** * Show more keys panel. * diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index a75b8f9e6..fc92a24a6 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -76,6 +76,8 @@ public class PointerTracker { public void startKeyRepeatTimer(long delay, PointerTracker tracker); public void startLongPressTimer(long delay, PointerTracker tracker); public void cancelLongPressTimer(); + public void startDoubleTapTimer(); + public boolean isInDoubleTapTimeout(); public void cancelKeyTimers(); public static class Adapter implements TimerProxy { @@ -90,6 +92,10 @@ public class PointerTracker { @Override public void cancelLongPressTimer() {} @Override + public void startDoubleTapTimer() {} + @Override + public boolean isInDoubleTapTimeout() { return false; } + @Override public void cancelKeyTimers() {} } } @@ -705,7 +711,7 @@ public class PointerTracker { if (sParams.mLongPressSpaceKeyTimeout > 0) { mTimerProxy.startLongPressTimer(sParams.mLongPressSpaceKeyTimeout, this); } - } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { + } else if (key.hasShiftedLetterHint() && mKeyboard.isManualShifted()) { // We need not start long press timer on the key which has manual temporary upper case // code defined and the keyboard is in manual temporary upper case mode. return; @@ -727,13 +733,6 @@ public class PointerTracker { final int[] codes = mKeyDetector.newCodeArray(); mKeyDetector.getKeyAndNearbyCodes(x, y, codes); - // If keyboard is in manual temporary upper case state and key has manual temporary - // uppercase letter as key hint letter, alternate character code should be sent. - if (mKeyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter()) { - code = key.mHintLabel.charAt(0); - codes[0] = code; - } - // Swap the first and second values in the codes array if the primary code is not the // first value but the second value in the array. This happens when key debouncing is // in effect. diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java index 4608e22a5..5712df1fc 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java @@ -18,27 +18,27 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; -public class KeyboardShiftState { - private static final String TAG = KeyboardShiftState.class.getSimpleName(); +public class AlphabetShiftState { + private static final String TAG = AlphabetShiftState.class.getSimpleName(); private static final boolean DEBUG = false; - private static final int NORMAL = 0; + private static final int UNSHIFTED = 0; private static final int MANUAL_SHIFTED = 1; private static final int MANUAL_SHIFTED_FROM_AUTO = 2; - private static final int AUTO_SHIFTED = 3; + private static final int AUTOMATIC_SHIFTED = 3; private static final int SHIFT_LOCKED = 4; private static final int SHIFT_LOCK_SHIFTED = 5; - private int mState = NORMAL; + private int mState = UNSHIFTED; public void setShifted(boolean newShiftState) { final int oldState = mState; if (newShiftState) { switch (oldState) { - case NORMAL: + case UNSHIFTED: mState = MANUAL_SHIFTED; break; - case AUTO_SHIFTED: + case AUTOMATIC_SHIFTED: mState = MANUAL_SHIFTED_FROM_AUTO; break; case SHIFT_LOCKED: @@ -49,8 +49,8 @@ public class KeyboardShiftState { switch (oldState) { case MANUAL_SHIFTED: case MANUAL_SHIFTED_FROM_AUTO: - case AUTO_SHIFTED: - mState = NORMAL; + case AUTOMATIC_SHIFTED: + mState = UNSHIFTED; break; case SHIFT_LOCK_SHIFTED: mState = SHIFT_LOCKED; @@ -65,30 +65,30 @@ public class KeyboardShiftState { final int oldState = mState; if (newShiftLockState) { switch (oldState) { - case NORMAL: + case UNSHIFTED: case MANUAL_SHIFTED: case MANUAL_SHIFTED_FROM_AUTO: - case AUTO_SHIFTED: + case AUTOMATIC_SHIFTED: mState = SHIFT_LOCKED; break; } } else { - mState = NORMAL; + mState = UNSHIFTED; } if (DEBUG) Log.d(TAG, "setShiftLocked(" + newShiftLockState + "): " + toString(oldState) + " > " + this); } - public void setAutomaticTemporaryUpperCase() { + public void setAutomaticShifted() { final int oldState = mState; - mState = AUTO_SHIFTED; + mState = AUTOMATIC_SHIFTED; if (DEBUG) - Log.d(TAG, "setAutomaticTemporaryUpperCase: " + toString(oldState) + " > " + this); + Log.d(TAG, "setAutomaticShifted: " + toString(oldState) + " > " + this); } public boolean isShiftedOrShiftLocked() { - return mState != NORMAL; + return mState != UNSHIFTED; } public boolean isShiftLocked() { @@ -99,16 +99,16 @@ public class KeyboardShiftState { return mState == SHIFT_LOCK_SHIFTED; } - public boolean isAutomaticTemporaryUpperCase() { - return mState == AUTO_SHIFTED; + public boolean isAutomaticShifted() { + return mState == AUTOMATIC_SHIFTED; } - public boolean isManualTemporaryUpperCase() { + public boolean isManualShifted() { return mState == MANUAL_SHIFTED || mState == MANUAL_SHIFTED_FROM_AUTO || mState == SHIFT_LOCK_SHIFTED; } - public boolean isManualTemporaryUpperCaseFromAuto() { + public boolean isManualShiftedFromAutomaticShifted() { return mState == MANUAL_SHIFTED_FROM_AUTO; } @@ -119,13 +119,13 @@ public class KeyboardShiftState { private static String toString(int state) { switch (state) { - case NORMAL: return "NORMAL"; + case UNSHIFTED: return "UNSHIFTED"; case MANUAL_SHIFTED: return "MANUAL_SHIFTED"; case MANUAL_SHIFTED_FROM_AUTO: return "MANUAL_SHIFTED_FROM_AUTO"; - case AUTO_SHIFTED: return "AUTO_SHIFTED"; + case AUTOMATIC_SHIFTED: return "AUTOMATIC_SHIFTED"; case SHIFT_LOCKED: return "SHIFT_LOCKED"; case SHIFT_LOCK_SHIFTED: return "SHIFT_LOCK_SHIFTED"; - default: return "UKNOWN"; + default: return "UNKNOWN"; } } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 5542bd32a..1de83866f 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -51,6 +51,9 @@ public class KeyboardState { * Request to call back {@link KeyboardState#onUpdateShiftState(boolean)}. */ public void requestUpdatingShiftState(); + + public void startDoubleTapTimer(); + public boolean isInDoubleTapTimeout(); } private final SwitchActions mSwitchActions; @@ -70,24 +73,28 @@ public class KeyboardState { private String mLayoutSwitchBackSymbols; private boolean mIsAlphabetMode; - private KeyboardShiftState mAlphabetShiftState = new KeyboardShiftState(); + private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState(); private boolean mIsSymbolShifted; private boolean mPrevMainKeyboardWasShiftLocked; private boolean mPrevSymbolsKeyboardWasShifted; + // For handling double tap. + private boolean mIsInAlphabetUnshiftedFromShifted; + private boolean mIsInDoubleTapShiftKey; + private final SavedKeyboardState mSavedKeyboardState = new SavedKeyboardState(); static class SavedKeyboardState { public boolean mIsValid; public boolean mIsAlphabetMode; - public boolean mIsShiftLocked; + public boolean mIsAlphabetShiftLocked; public boolean mIsShifted; @Override public String toString() { if (!mIsValid) return "INVALID"; if (mIsAlphabetMode) { - if (mIsShiftLocked) return "ALPHABET_SHIFT_LOCKED"; + if (mIsAlphabetShiftLocked) return "ALPHABET_SHIFT_LOCKED"; return mIsShifted ? "ALPHABET_SHIFTED" : "ALPHABET"; } else { return mIsShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS"; @@ -117,11 +124,11 @@ public class KeyboardState { final SavedKeyboardState state = mSavedKeyboardState; state.mIsAlphabetMode = mIsAlphabetMode; if (mIsAlphabetMode) { - state.mIsShiftLocked = mAlphabetShiftState.isShiftLocked(); - state.mIsShifted = !state.mIsShiftLocked + state.mIsAlphabetShiftLocked = mAlphabetShiftState.isShiftLocked(); + state.mIsShifted = !state.mIsAlphabetShiftLocked && mAlphabetShiftState.isShiftedOrShiftLocked(); } else { - state.mIsShiftLocked = false; + state.mIsAlphabetShiftLocked = mPrevMainKeyboardWasShiftLocked; state.mIsShifted = mIsSymbolShifted; } state.mIsValid = true; @@ -149,10 +156,12 @@ public class KeyboardState { state.mIsValid = false; if (state.mIsAlphabetMode) { - setShiftLocked(state.mIsShiftLocked); - if (!state.mIsShiftLocked) { + setShiftLocked(state.mIsAlphabetShiftLocked); + if (!state.mIsAlphabetShiftLocked) { setShifted(state.mIsShifted ? MANUAL_SHIFT : UNSHIFT); } + } else { + mPrevMainKeyboardWasShiftLocked = state.mIsAlphabetShiftLocked; } } @@ -167,16 +176,16 @@ public class KeyboardState { } if (!mIsAlphabetMode) return; final int prevShiftMode; - if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) { + if (mAlphabetShiftState.isAutomaticShifted()) { prevShiftMode = AUTOMATIC_SHIFT; - } else if (mAlphabetShiftState.isManualTemporaryUpperCase()) { + } else if (mAlphabetShiftState.isManualShifted()) { prevShiftMode = MANUAL_SHIFT; } else { prevShiftMode = UNSHIFT; } switch (shiftMode) { case AUTOMATIC_SHIFT: - mAlphabetShiftState.setAutomaticTemporaryUpperCase(); + mAlphabetShiftState.setAutomaticShifted(); if (shiftMode != prevShiftMode) { mSwitchActions.setAlphabetAutomaticShiftedKeyboard(); } @@ -256,8 +265,7 @@ public class KeyboardState { mSwitchActions.requestUpdatingShiftState(); } - // TODO: Make this method private - public void setSymbolsKeyboard() { + private void setSymbolsKeyboard() { if (DEBUG_ACTION) { Log.d(TAG, "setSymbolsKeyboard"); } @@ -348,22 +356,35 @@ public class KeyboardState { private void onPressShift() { if (mIsAlphabetMode) { - if (mAlphabetShiftState.isShiftLocked()) { - // Shift key is pressed while caps lock state, we will treat this state as shifted - // caps lock state and mark as if shift key pressed while normal state. + mIsInDoubleTapShiftKey = mSwitchActions.isInDoubleTapTimeout(); + if (!mIsInDoubleTapShiftKey) { + // This is first tap. + mSwitchActions.startDoubleTapTimer(); + } + if (mIsInDoubleTapShiftKey) { + if (mAlphabetShiftState.isManualShifted() || mIsInAlphabetUnshiftedFromShifted) { + // Shift key has been double tapped while in manual shifted or automatic + // shifted state. + setShiftLocked(true); + } else { + // Shift key has been double tapped while in normal state. This is the second + // tap to disable shift locked state, so just ignore this. + } + } else if (mAlphabetShiftState.isShiftLocked()) { + // Shift key is pressed while shift locked state, we will treat this state as + // shift lock shifted state and mark as if shift key pressed while normal state. setShifted(SHIFT_LOCK_SHIFTED); mShiftKeyState.onPress(); - } else if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) { - // Shift key is pressed while automatic temporary upper case, we have to move to - // manual temporary upper case. + } else if (mAlphabetShiftState.isAutomaticShifted()) { + // Shift key is pressed while automatic shifted, we have to move to manual shifted. setShifted(MANUAL_SHIFT); mShiftKeyState.onPress(); } else if (mAlphabetShiftState.isShiftedOrShiftLocked()) { - // In manual upper case state, we just record shift key has been pressing while + // In manual shifted state, we just record shift key has been pressing while // shifted state. mShiftKeyState.onPressOnShifted(); } else { - // In base layout, chording or manual temporary upper case mode is started. + // In base layout, chording or manual shifted mode is started. setShifted(MANUAL_SHIFT); mShiftKeyState.onPress(); } @@ -378,33 +399,40 @@ public class KeyboardState { private void onReleaseShift(boolean withSliding) { if (mIsAlphabetMode) { final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked(); - if (mShiftKeyState.isChording()) { + mIsInAlphabetUnshiftedFromShifted = false; + if (mIsInDoubleTapShiftKey) { + // Double tap shift key has been handled in {@link #onPressShift}, so that just + // ignore this release shift key here. + mIsInDoubleTapShiftKey = false; + } else if (mShiftKeyState.isChording()) { if (mAlphabetShiftState.isShiftLockShifted()) { - // After chording input while caps lock state. + // After chording input while shift locked state. setShiftLocked(true); } else { // After chording input while normal state. setShifted(UNSHIFT); } } else if (mAlphabetShiftState.isShiftLockShifted() && withSliding) { - // In caps lock state, shift has been pressed and slid out to other key. + // In shift locked state, shift has been pressed and slid out to other key. setShiftLocked(true); } else if (isShiftLocked && !mAlphabetShiftState.isShiftLockShifted() && (mShiftKeyState.isPressing() || mShiftKeyState.isPressingOnShifted()) && !withSliding) { // Shift has been long pressed, ignore this release. } else if (isShiftLocked && !mShiftKeyState.isIgnoring() && !withSliding) { - // Shift has been pressed without chording while caps lock state. + // Shift has been pressed without chording while shift locked state. setShiftLocked(false); } else if (mAlphabetShiftState.isShiftedOrShiftLocked() && mShiftKeyState.isPressingOnShifted() && !withSliding) { // Shift has been pressed without chording while shifted state. setShifted(UNSHIFT); - } else if (mAlphabetShiftState.isManualTemporaryUpperCaseFromAuto() + mIsInAlphabetUnshiftedFromShifted = true; + } else if (mAlphabetShiftState.isManualShiftedFromAutomaticShifted() && mShiftKeyState.isPressing() && !withSliding) { - // Shift has been pressed without chording while manual temporary upper case - // transited from automatic temporary upper case. + // Shift has been pressed without chording while manual shifted transited from + // automatic shifted setShifted(UNSHIFT); + mIsInAlphabetUnshiftedFromShifted = true; } } else { // In symbol mode, switch back to the previous keyboard mode if the user chords the @@ -455,10 +483,11 @@ public class KeyboardState { if (mIsAlphabetMode && code == Keyboard.CODE_CAPSLOCK) { if (mAlphabetShiftState.isShiftLocked()) { setShiftLocked(false); - // Shift key is long pressed or double tapped while caps lock state, we will - // toggle back to normal state. And mark as if shift key is released. + // Shift key is long pressed while shift locked state, we will toggle back to normal + // state. And mark as if shift key is released. mShiftKeyState.onRelease(); } else { + // Shift key is long pressed while shift unloked state. setShiftLocked(true); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2e7e82637..1e7171406 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -291,8 +291,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar latinIme.updateBigramPredictions(); break; case MSG_VOICE_RESULTS: + final Keyboard keyboard = switcher.getKeyboard(); latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization() - || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked())); + || (keyboard != null && keyboard.isShiftedOrShiftLocked())); break; case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR: setSpacebarTextFadeFactor(inputView, @@ -987,8 +988,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { // TODO: Modify this if we support suggestions with hard keyboard if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { + final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + final boolean inputViewShown = (keyboardView != null) ? keyboardView.isShown() : false; final boolean shouldShowSuggestions = shown - && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true); + && (needsInputViewShown ? inputViewShown : true); if (isFullscreenMode()) { mSuggestionsContainer.setVisibility( shouldShowSuggestions ? View.VISIBLE : View.GONE); @@ -1020,7 +1023,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final int extraHeight = extractHeight + backingHeight + suggestionsHeight; int touchY = extraHeight; // Need to set touchable region only if input view is being shown - if (mKeyboardSwitcher.isInputViewShown()) { + final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + if (keyboardView != null && keyboardView.isShown()) { if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { touchY -= suggestionsHeight; } @@ -1081,9 +1085,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: + final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); // Enable shift key and DPAD to do selections - if (mKeyboardSwitcher.isInputViewShown() - && mKeyboardSwitcher.isShiftedOrShiftLocked()) { + if ((keyboardView != null && keyboardView.isShown()) + && (keyboard != null && keyboard.isShiftedOrShiftLocked())) { KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(), event.getAction(), event.getKeyCode(), event.getRepeatCount(), event.getDeviceId(), event.getScanCode(), @@ -1470,13 +1476,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ic == null) return; - // True if keyboard is in either chording shift or manual temporary upper case mode. - final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase(); - if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) - && !isManualTemporaryUpperCase) { + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); + // True if keyboard is in either shift chording or manual shifted state. + final boolean isManualShifted = (keyboard != null && keyboard.isManualShifted()); + if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) && !isManualShifted) { EditorInfoCompatUtils.performEditorActionNext(ic); - } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions) - && isManualTemporaryUpperCase) { + } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions) && isManualShifted) { EditorInfoCompatUtils.performEditorActionPrevious(ic); } } @@ -1518,27 +1523,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mComposingStateManager.onFinishComposingText(); } } - final KeyboardSwitcher switcher = mKeyboardSwitcher; - if (switcher.isShiftedOrShiftLocked()) { - if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT - || keyCodes[0] > Character.MAX_CODE_POINT) { - return; - } - code = keyCodes[0]; - if (switcher.isAlphabetMode() && Character.isLowerCase(code)) { - // In some locales, such as Turkish, Character.toUpperCase() may return a wrong - // character because it doesn't take care of locale. - final String upperCaseString = new String(new int[] {code}, 0, 1) - .toUpperCase(mSubtypeSwitcher.getInputLocale()); - if (upperCaseString.codePointCount(0, upperCaseString.length()) == 1) { - code = upperCaseString.codePointAt(0); - } else { - // Some keys, such as [eszett], have upper case as multi-characters. - onTextInput(upperCaseString); - return; - } - } - } if (isComposingWord) { mWordComposer.add(code, keyCodes, x, y); if (ic != null) { diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index 600f14e04..cd83c3e21 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -141,11 +141,6 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { } @Override - public void setShifted(boolean shifted) { - // Nothing to do with. - } - - @Override public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, PopupWindow window, KeyboardActionListener listener) { mController = controller; |