aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java131
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java26
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java2
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java2
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java6
5 files changed, 127 insertions, 40 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 8627508e5..55041154d 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -57,6 +57,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private LatinKeyboardView mInputView;
private LatinIME mInputMethodService;
+ // TODO: Combine these key state objects with auto mode switch state.
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
@@ -75,13 +76,17 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private boolean mVoiceKeyEnabled;
private boolean mVoiceButtonOnPrimary;
- private static final int AUTO_MODE_SWITCH_STATE_ALPHA = 0;
- private static final int AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN = 1;
- private static final int AUTO_MODE_SWITCH_STATE_SYMBOL = 2;
+ // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState
+ // and ModifierKeyState.
+ private static final int SWITCH_STATE_ALPHA = 0;
+ private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
+ private static final int SWITCH_STATE_SYMBOL = 2;
// The following states are used only on the distinct multi-touch panel devices.
- private static final int AUTO_MODE_SWITCH_STATE_MOMENTARY = 3;
- private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4;
- private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
+ private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
+ private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
+ private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
+ private int mSwitchState = SWITCH_STATE_ALPHA;
// Indicates whether or not we have the settings key in option of settings
private boolean mSettingsKeyEnabledInSettings;
@@ -124,7 +129,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void loadKeyboard(EditorInfo attribute, boolean voiceKeyEnabled,
boolean voiceButtonOnPrimary) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ mSwitchState = SWITCH_STATE_ALPHA;
try {
loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false);
} catch (RuntimeException e) {
@@ -466,6 +471,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// In symbol mode, just toggle symbol and symbol more keyboard.
shiftKeyState.onPress();
toggleShift();
+ mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
}
}
@@ -487,6 +493,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !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.
+ mInputView.startIgnoringDoubleTap();
} else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()
&& !withSliding) {
// Shift has been pressed without chording while shifted state.
@@ -497,6 +507,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// transited from automatic temporary upper case.
toggleShift();
}
+ } else {
+ // In symbol mode, snap back to the previous keyboard mode if the user chords the shift
+ // key and another key, then releases the shift key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
+ toggleShift();
+ }
}
shiftKeyState.onRelease();
}
@@ -511,7 +527,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
+ " symbolKeyState=" + mSymbolKeyState);
changeKeyboardMode();
mSymbolKeyState.onPress();
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_MOMENTARY;
+ mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
}
public void onReleaseSymbol() {
@@ -523,9 +539,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
+ " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ " symbolKeyState=" + mSymbolKeyState);
// Snap back to the previous keyboard mode if the user chords the mode change key and
- // other key, then released the mode change key.
- if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_CHORDING)
+ // another key, then releases the mode change key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
changeKeyboardMode();
+ }
mSymbolKeyState.onRelease();
}
@@ -544,8 +561,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void onCancelInput() {
// Snap back to the previous keyboard mode if the user cancels sliding input.
- if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY && getPointerCount() == 1)
- changeKeyboardMode();
+ if (getPointerCount() == 1) {
+ if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
+ changeKeyboardMode();
+ } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
+ toggleShift();
+ }
+ }
}
private void toggleShiftInSymbol() {
@@ -568,8 +590,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
setKeyboard(keyboard);
}
- public boolean isInMomentaryAutoModeSwitchState() {
- return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY;
+ public boolean isInMomentarySwitchState() {
+ return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
+ || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
}
public boolean isVibrateAndSoundFeedbackRequired() {
@@ -583,9 +606,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private void toggleKeyboardMode() {
loadKeyboardInternal(mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary, !mIsSymbols);
if (mIsSymbols) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ mSwitchState = SWITCH_STATE_ALPHA;
}
}
@@ -597,28 +620,52 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mInputView != null && mInputView.hasDistinctMultitouch();
}
+ private static boolean isSpaceCharacter(int c) {
+ return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
+ }
+
+ private static boolean isQuoteCharacter(int c) {
+ // Apostrophe, quotation mark.
+ if (c == '\'' || c == '"')
+ return true;
+ // \u2018: Left single quotation mark
+ // \u2019: Right single quotation mark
+ // \u201a: Single low-9 quotation mark
+ // \u201b: Single high-reversed-9 quotation mark
+ // \u201c: Left double quotation mark
+ // \u201d: Right double quotation mark
+ // \u201e: Double low-9 quotation mark
+ // \u201f: Double high-reversed-9 quotation mark
+ if (c >= '\u2018' && c <= '\u201f')
+ return true;
+ // \u00ab: Left-pointing double angle quotation mark
+ // \u00bb: Right-pointing double angle quotation mark
+ if (c == '\u00ab' || c == '\u00bb')
+ return true;
+ return false;
+ }
+
/**
* Updates state machine to figure out when to automatically snap back to the previous mode.
*/
- public void onKey(int key) {
+ public void onKey(int code) {
if (DEBUG_STATE)
- Log.d(TAG, "onKey: code=" + key + " autoModeSwitchState=" + mAutoModeSwitchState
+ Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState
+ " pointers=" + getPointerCount());
- switch (mAutoModeSwitchState) {
- case AUTO_MODE_SWITCH_STATE_MOMENTARY:
+ switch (mSwitchState) {
+ case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
// Only distinct multi touch devices can be in this state.
// On non-distinct multi touch devices, mode change key is handled by
// {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
- // {@link LatinIME#onRelease}. So, on such devices, {@link #mAutoModeSwitchState} starts
- // from {@link #AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, or
- // {@link #AUTO_MODE_SWITCH_STATE_ALPHA}, not from
- // {@link #AUTO_MODE_SWITCH_STATE_MOMENTARY}.
- if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
+ // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
+ // {@link #SWITCH_STATE_MOMENTARY}.
+ if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released.
if (mIsSymbols) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ mSwitchState = SWITCH_STATE_ALPHA;
}
} else if (getPointerCount() == 1) {
// Snap back to the previous keyboard mode if the user pressed the mode change key
@@ -629,18 +676,34 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else {
// Chording input is being started. The keyboard mode will be snapped back to the
// previous mode in {@link onReleaseSymbol} when the mode change key is released.
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING;
+ mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
+ }
+ break;
+ case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
+ if (code == Keyboard.CODE_SHIFT) {
+ // Detected only the shift key has been pressed on symbol layout, and then released.
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
+ } else if (getPointerCount() == 1) {
+ // Snap back to the previous keyboard mode if the user pressed the shift key on
+ // symbol mode and slid to other key, then released the finger.
+ toggleShift();
+ mSwitchState = SWITCH_STATE_SYMBOL;
+ } else {
+ // Chording input is being started. The keyboard mode will be snapped back to the
+ // previous mode in {@link onReleaseShift} when the shift key is released.
+ mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
}
break;
- case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN:
- if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key >= 0) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL;
+ case SWITCH_STATE_SYMBOL_BEGIN:
+ if (!isSpaceCharacter(code) && code >= 0) {
+ mSwitchState = SWITCH_STATE_SYMBOL;
}
break;
- case AUTO_MODE_SWITCH_STATE_SYMBOL:
+ case SWITCH_STATE_SYMBOL:
+ case SWITCH_STATE_CHORDING_SYMBOL:
// Snap back to alpha keyboard mode if user types one or more non-space/enter
- // characters followed by a space/enter.
- if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) {
+ // characters followed by a space/enter or quotation mark.
+ if (isSpaceCharacter(code) || isQuoteCharacter(code)) {
changeKeyboardMode();
}
break;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index c36895258..11476e069 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -44,6 +44,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -73,7 +74,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private static final boolean DEBUG_SHOW_ALIGN = false;
private static final boolean DEBUG_KEYBOARD_GRID = false;
- private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = false;
+ private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = true;
private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true;
public static final int COLOR_SCHEME_WHITE = 0;
@@ -189,6 +190,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private static final int MSG_REPEAT_KEY = 3;
private static final int MSG_LONGPRESS_KEY = 4;
private static final int MSG_LONGPRESS_SHIFT_KEY = 5;
+ private static final int MSG_IGNORE_DOUBLE_TAP = 6;
private boolean mInKeyRepeat;
@@ -286,6 +288,16 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
public void cancelKeyTimers() {
cancelKeyRepeatTimer();
cancelLongPressTimers();
+ removeMessages(MSG_IGNORE_DOUBLE_TAP);
+ }
+
+ public void startIgnoringDoubleTap() {
+ sendMessageDelayed(obtainMessage(MSG_IGNORE_DOUBLE_TAP),
+ ViewConfiguration.getDoubleTapTimeout());
+ }
+
+ public boolean isIgnoringDoubleTap() {
+ return hasMessages(MSG_IGNORE_DOUBLE_TAP);
}
public void cancelAllMessages() {
@@ -449,7 +461,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
final PointerTracker tracker = getPointerTracker(id);
// If the second down event is also on shift key.
if (tracker.isOnShiftKey((int)secondDown.getX(), (int)secondDown.getY())) {
- onDoubleTapShiftKey(tracker);
+ // 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} .
+ final boolean ignoringDoubleTap = mHandler.isIgnoringDoubleTap();
+ if (!ignoringDoubleTap)
+ onDoubleTapShiftKey(tracker);
return true;
}
// Otherwise these events should not be handled as double tap.
@@ -468,6 +485,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
}
+ public void startIgnoringDoubleTap() {
+ if (ENABLE_CAPSLOCK_BY_DOUBLETAP)
+ mHandler.startIgnoringDoubleTap();
+ }
+
public void setOnKeyboardActionListener(KeyboardActionListener listener) {
mKeyboardActionListener = listener;
for (PointerTracker tracker : mPointerTrackers) {
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index e3161f610..abd1ef286 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -662,7 +662,7 @@ public class PointerTracker {
// 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;
- } else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) {
+ } else if (mKeyboardSwitcher.isInMomentarySwitchState()) {
// We use longer timeout for sliding finger input started from the symbols mode key.
mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this);
} else {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 175467fcb..39bc78e20 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -112,7 +112,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private static final int DELAY_UPDATE_SUGGESTIONS = 180;
private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
- private static final int DELAY_UPDATE_SHIFT_STATE = 300;
+ private static final int DELAY_UPDATE_SHIFT_STATE = 100;
private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
// How many continuous deletes at which to start deleting at a higher speed.
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 9d7b98410..d165de32d 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -50,6 +50,7 @@ public class Utils {
private static final String TAG = Utils.class.getSimpleName();
private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
private static boolean DBG = LatinImeLogger.sDBG;
+ private static boolean DBG_EDIT_DISTANCE = false;
private Utils() {
// Intentional empty constructor for utility class.
@@ -291,7 +292,7 @@ public class Utils {
}
}
}
- if (LatinImeLogger.sDBG) {
+ if (DBG_EDIT_DISTANCE) {
Log.d(TAG, "editDistance:" + s + "," + t);
for (int i = 0; i < dp.length; ++i) {
StringBuffer sb = new StringBuffer();
@@ -340,6 +341,7 @@ public class Utils {
private static final int MAX_INITIAL_SCORE = 255;
private static final int TYPED_LETTER_MULTIPLIER = 2;
private static final int FULL_WORD_MULTIPLIER = 2;
+ private static final int S_INT_MAX = 2147483647;
public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) {
final int beforeLength = before.length();
final int afterLength = after.length();
@@ -354,7 +356,7 @@ public class Utils {
}
}
if (spaceCount == afterLength) return 0;
- final double maximumScore = MAX_INITIAL_SCORE
+ final double maximumScore = score == S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE
* Math.pow(
TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength - spaceCount))
* FULL_WORD_MULTIPLIER;