diff --git a/dictionaries/en_whitelist.xml b/dictionaries/en_whitelist.xml
new file mode 100644
index 000000000..e11935fdf
--- /dev/null
+++ b/dictionaries/en_whitelist.xml
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/proguard.flags b/java/proguard.flags
index 24b4c1987..ac5b7df16 100644
--- a/java/proguard.flags
+++ b/java/proguard.flags
@@ -44,6 +44,10 @@
(...);
}
+-keepclasseswithmembernames class * {
+ native ;
+}
+
-keep class com.android.inputmethod.research.ResearchLogger {
void flush();
void publishCurrentLogUnit(...);
diff --git a/java/res/values-en/whitelist.xml b/java/res/values-en/whitelist.xml
deleted file mode 100644
index 262017916..000000000
--- a/java/res/values-en/whitelist.xml
+++ /dev/null
@@ -1,411 +0,0 @@
-
-
-
-
-
-
- - 255
- - ill
- - I\'ll
-
-
-
- - 255
- - acomodate
- - accommodate
-
- - 255
- - aint
- - ain\'t
-
- - 255
- - alot
- - a lot
-
- - 255
- - andteh
- - and the
-
- - 255
- - arent
- - aren\'t
-
- - 255
- - bot
- - not
-
- - 255
- - bern
- - been
-
- - 255
- - bot
- - not
-
- - 255
- - bur
- - but
-
- - 255
- - cam
- - can
-
- - 255
- - cant
- - can\'t
-
- - 255
- - dame
- - same
-
- - 255
- - didint
- - didn\'t
-
- - 255
- - dormer
- - former
-
- - 255
- - dud
- - did
-
- - 255
- - fay
- - day
-
- - 255
- - fife
- - five
-
- - 255
- - foo
- - for
-
- - 255
- - fora
- - for a
-
- - 255
- - galled
- - called
-
- - 255
- - goo
- - too
-
- - 255
- - hed
- - he\'d
-
- - 255
- - hel
- - he\'ll
-
- - 255
- - heres
- - here\'s
-
- - 255
- - hew
- - new
-
- - 255
- - hoe
- - how
-
- - 255
- - hoes
- - how\'s
-
- - 255
- - howd
- - how\'d
-
- - 255
- - howll
- - how\'ll
-
- - 255
- - hows
- - how\'s
-
- - 255
- - howve
- - how\'ve
-
- - 255
- - hum
- - him
-
- - 255
- - i
- - I
-
- - 255
- - ifs
- - its
-
- - 255
- - il
- - I\'ll
-
- - 255
- - im
- - I\'m
-
- - 255
- - inteh
- - in the
-
- - 255
- - itd
- - it\'d
-
- - 255
- - itsa
- - it\'s a
-
- - 255
- - lets
- - let\'s
-
- - 255
- - maam
- - ma\'am
-
- - 255
- - manu
- - many
-
- - 255
- - mare
- - made
-
- - 255
- - mew
- - new
-
- - 255
- - mire
- - more
-
- - 255
- - moat
- - most
-
- - 255
- - mot
- - not
-
- - 255
- - mote
- - note
-
- - 255
- - motes
- - notes
-
- - 255
- - mow
- - now
-
- - 255
- - namer
- - named
-
- - 255
- - nave
- - have
-
- - 255
- - nee
- - new
-
- - 255
- - nigh
- - high
-
- - 255
- - nit
- - not
-
- - 255
- - oft
- - off
-
- - 255
- - os
- - is
-
- - 255
- - pater
- - later
-
- - 255
- - rook
- - took
-
- - 255
- - shel
- - she\'ll
-
- - 255
- - shouldent
- - shouldn\'t
-
- - 255
- - sill
- - will
-
- - 255
- - sown
- - down
-
- - 255
- - thatd
- - that\'d
-
- - 255
- - tine
- - time
-
- - 255
- - thong
- - thing
-
- - 255
- - tome
- - time
-
-
- - 255
- - uf
- - if
-
-
- - 255
- - un
- - in
-
-
- - 255
- - UnitedStates
- - United States
-
- - 255
- - unitedstates
- - United States
-
- - 255
- - visavis
- - vis-a-vis
-
- - 255
- - wierd
- - weird
-
- - 255
- - wel
- - we\'ll
-
- - 255
- - wer
- - we\'re
-
- - 255
- - whatd
- - what\'d
-
- - 255
- - whatm
- - what\'m
-
- - 255
- - whatre
- - what\'re
-
- - 255
- - whats
- - what\'s
-
- - 255
- - whens
- - when\'s
-
- - 255
- - whered
- - where\'d
-
- - 255
- - wherell
- - where\'ll
-
- - 255
- - wheres
- - where\'s
-
- - 255
- - wholl
- - who\'ll
-
- - 255
- - whove
- - who\'ve
-
- - 255
- - whyd
- - why\'d
-
- - 255
- - whyll
- - why\'ll
-
- - 255
- - whys
- - why\'s
-
- - 255
- - whyve
- - why\'ve
-
- - 255
- - wont
- - won\'t
-
- - 255
- - yall
- - y\'all
-
- - 255
- - youd
- - you\'d
-
-
-
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 4975d6540..76e76cc82 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -41,26 +41,24 @@
checkable+checked+pressed. -->
-
-
-
-
-
-
+
+
+
+
-
-
-
+
-
+
-
+
-
+
-
+
+
@@ -96,8 +94,8 @@
-
-
+
+
@@ -131,6 +129,12 @@
+
+
+
+
+
+
@@ -181,13 +185,13 @@
-
-
-
-
-
+
+
+
+
+
-
+
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 54a6687a3..8e2d43e4e 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -50,6 +50,9 @@
-->
70
200
+ 100
+ 800
+ 20
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index c59bad302..4fd942b14 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -92,7 +92,7 @@
18dp
27dp
3
- 36
+ 36%
2.5dp
@@ -101,4 +101,7 @@
17.5dp
7.5dp
1.0dp
+
+
+ 8dp
diff --git a/java/res/values/keypress-vibration-durations.xml b/java/res/values/keypress-vibration-durations.xml
index 2569f2317..8f6b647b7 100644
--- a/java/res/values/keypress-vibration-durations.xml
+++ b/java/res/values/keypress-vibration-durations.xml
@@ -22,5 +22,6 @@
- herring,5
- tuna,5
+ - mako,20
diff --git a/java/res/values/keypress-volumes.xml b/java/res/values/keypress-volumes.xml
index 3b433e4ab..dd86d6c38 100644
--- a/java/res/values/keypress-volumes.xml
+++ b/java/res/values/keypress-volumes.xml
@@ -24,5 +24,6 @@
- tuna,0.5
- stingray,0.4
- grouper,0.3
+ - mako,0.3
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 07b3f31c7..35cbcf3c4 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -261,7 +261,8 @@
Send feedback
- Include last 5 words entered
+
+ Include last %d words entered
Enter your feedback here.
@@ -288,6 +289,10 @@
Send usage info
+
+
+ Research Uploader Service
+
Input languages
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index ae67c4369..0220c836e 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -35,9 +35,9 @@
@@ -370,12 +373,12 @@
- @android:color/holo_blue_light
- @android:color/holo_blue_light
- @android:color/holo_blue_light
- - 85
- - 85
- - 70
- - 70
+ - 85%
+ - 85%
+ - 70%
+ - 70%
- @integer/suggestions_count_in_strip
- - @integer/center_suggestion_percentile
+ - @fraction/center_suggestion_percentile
- @integer/max_more_suggestions_row
- @fraction/min_more_suggestions_width
diff --git a/java/res/values/whitelist.xml b/java/res/values/whitelist.xml
deleted file mode 100644
index d4ecbfaa4..000000000
--- a/java/res/values/whitelist.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index 70e38fdb0..039c77b9c 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -35,6 +35,7 @@ import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardView;
+import com.android.inputmethod.latin.CollectionUtils;
/**
* Exposes a virtual view sub-tree for {@link KeyboardView} and generates
@@ -55,7 +56,7 @@ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat
private final AccessibilityUtils mAccessibilityUtils;
/** A map of integer IDs to {@link Key}s. */
- private final SparseArray mVirtualViewIdToKey = new SparseArray();
+ private final SparseArray mVirtualViewIdToKey = CollectionUtils.newSparseArray();
/** Temporary rect used to calculate in-screen bounds. */
private final Rect mTempBoundsInScreen = new Rect();
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index 616b1c6d7..58d3022c9 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -19,10 +19,15 @@ package com.android.inputmethod.accessibility;
import android.content.Context;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
+import android.os.Build;
import android.os.SystemClock;
import android.provider.Settings;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.EditorInfo;
@@ -138,9 +143,10 @@ public class AccessibilityUtils {
* Sends the specified text to the {@link AccessibilityManager} to be
* spoken.
*
- * @param text the text to speak
+ * @param view The source view.
+ * @param text The text to speak.
*/
- public void speak(CharSequence text) {
+ public void announceForAccessibility(View view, CharSequence text) {
if (!mAccessibilityManager.isEnabled()) {
Log.e(TAG, "Attempted to speak when accessibility was disabled!");
return;
@@ -149,8 +155,7 @@ public class AccessibilityUtils {
// The following is a hack to avoid using the heavy-weight TextToSpeech
// class. Instead, we're just forcing a fake AccessibilityEvent into
// the screen reader to make it speak.
- final AccessibilityEvent event = AccessibilityEvent
- .obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ final AccessibilityEvent event = AccessibilityEvent.obtain();
event.setPackageName(PACKAGE);
event.setClassName(CLASS);
@@ -158,20 +163,34 @@ public class AccessibilityUtils {
event.setEnabled(true);
event.getText().add(text);
- mAccessibilityManager.sendAccessibilityEvent(event);
+ // Platforms starting at SDK 16 should use announce events.
+ if (Build.VERSION.SDK_INT >= 16) {
+ event.setEventType(AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
+ } else {
+ event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ }
+
+ final ViewParent viewParent = view.getParent();
+ if ((viewParent == null) || !(viewParent instanceof ViewGroup)) {
+ Log.e(TAG, "Failed to obtain ViewParent in announceForAccessibility");
+ return;
+ }
+
+ viewParent.requestSendAccessibilityEvent(view, event);
}
/**
* Handles speaking the "connect a headset to hear passwords" notification
* when connecting to a password field.
*
+ * @param view The source view.
* @param editorInfo The input connection's editor info attribute.
* @param restarting Whether the connection is being restarted.
*/
- public void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) {
+ public void onStartInputViewInternal(View view, EditorInfo editorInfo, boolean restarting) {
if (shouldObscureInput(editorInfo)) {
final CharSequence text = mContext.getText(R.string.spoken_use_headphones);
- speak(text);
+ announceForAccessibility(view, text);
}
}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index 4ecbf827a..e42de0b4c 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -24,7 +24,6 @@ import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
@@ -44,7 +43,7 @@ public class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
/**
* Inset in pixels to look for keys when the user's finger exits the
- * keyboard area. See {@link ViewConfiguration#getScaledEdgeSlop()}.
+ * keyboard area.
*/
private int mEdgeSlop;
@@ -62,7 +61,8 @@ public class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
private void initInternal(InputMethodService inputMethod) {
mInputMethod = inputMethod;
- mEdgeSlop = ViewConfiguration.get(inputMethod).getScaledEdgeSlop();
+ mEdgeSlop = inputMethod.getResources().getDimensionPixelSize(
+ R.dimen.accessibility_edge_slop);
}
/**
@@ -114,8 +114,14 @@ public class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
public boolean dispatchHoverEvent(MotionEvent event, PointerTracker tracker) {
final int x = (int) event.getX();
final int y = (int) event.getY();
- final Key key = tracker.getKeyOn(x, y);
final Key previousKey = mLastHoverKey;
+ final Key key;
+
+ if (pointInView(x, y)) {
+ key = tracker.getKeyOn(x, y);
+ } else {
+ key = null;
+ }
mLastHoverKey = key;
@@ -123,7 +129,7 @@ public class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
case MotionEvent.ACTION_HOVER_EXIT:
// Make sure we're not getting an EXIT event because the user slid
// off the keyboard area, then force a key press.
- if (pointInView(x, y) && (key != null)) {
+ if (key != null) {
getAccessibilityNodeProvider().simulateKeyPress(key);
}
//$FALL-THROUGH$
@@ -250,7 +256,7 @@ public class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
text = context.getText(R.string.spoken_description_shiftmode_off);
}
- AccessibilityUtils.getInstance().speak(text);
+ AccessibilityUtils.getInstance().announceForAccessibility(mView, text);
}
/**
@@ -290,6 +296,6 @@ public class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
}
final String text = context.getString(resId);
- AccessibilityUtils.getInstance().speak(text);
+ AccessibilityUtils.getInstance().announceForAccessibility(mView, text);
}
}
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
index 9b74070af..5c45448a5 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -25,6 +25,7 @@ import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.R;
import java.util.HashMap;
@@ -38,7 +39,7 @@ public class KeyCodeDescriptionMapper {
private static KeyCodeDescriptionMapper sInstance = new KeyCodeDescriptionMapper();
// Map of key labels to spoken description resource IDs
- private final HashMap mKeyLabelMap;
+ private final HashMap mKeyLabelMap = CollectionUtils.newHashMap();
// Sparse array of spoken description resource IDs indexed by key codes
private final SparseIntArray mKeyCodeMap;
@@ -52,7 +53,6 @@ public class KeyCodeDescriptionMapper {
}
private KeyCodeDescriptionMapper() {
- mKeyLabelMap = new HashMap();
mKeyCodeMap = new SparseIntArray();
}
diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
index 1183b5fb9..6ba309fcb 100644
--- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
+++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
@@ -16,10 +16,6 @@
package com.android.inputmethod.compat;
-import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.SuggestionSpanPickedNotificationReceiver;
-
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
@@ -27,6 +23,11 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
+import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.SuggestionSpanPickedNotificationReceiver;
+
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -119,7 +120,7 @@ public class SuggestionSpanUtils {
} else {
spannable = new SpannableString(pickedWord);
}
- final ArrayList suggestionsList = new ArrayList();
+ final ArrayList suggestionsList = CollectionUtils.newArrayList();
for (int i = 0; i < suggestedWords.size(); ++i) {
if (suggestionsList.size() >= OBJ_SUGGESTIONS_MAX_SIZE) {
break;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 97d88af4a..868c8cab5 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -16,10 +16,10 @@
package com.android.inputmethod.keyboard;
+import com.android.inputmethod.latin.Constants;
+
public class KeyDetector {
- public static final int NOT_A_CODE = -1;
-
private final int mKeyHysteresisDistanceSquared;
private Keyboard mKeyboard;
@@ -59,6 +59,9 @@ public class KeyDetector {
}
public Keyboard getKeyboard() {
+ if (mKeyboard == null) {
+ throw new IllegalStateException("keyboard isn't set");
+ }
return mKeyboard;
}
@@ -100,7 +103,7 @@ public class KeyDetector {
final StringBuilder sb = new StringBuilder();
boolean addDelimiter = false;
for (final int code : codes) {
- if (code == NOT_A_CODE) break;
+ if (code == Constants.NOT_A_CODE) break;
if (addDelimiter) sb.append(", ");
sb.append(Keyboard.printableCode(code));
addDelimiter = true;
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 3abe890cb..e37868b3f 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -33,6 +33,7 @@ import com.android.inputmethod.keyboard.internal.KeyStyles;
import com.android.inputmethod.keyboard.internal.KeyboardCodesSet;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardTextsSet;
+import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
import com.android.inputmethod.latin.R;
@@ -134,7 +135,7 @@ public class Keyboard {
public final Key[] mAltCodeKeysWhileTyping;
public final KeyboardIconsSet mIconsSet;
- private final SparseArray mKeyCache = new SparseArray();
+ private final SparseArray mKeyCache = CollectionUtils.newSparseArray();
private final ProximityInfo mProximityInfo;
private final boolean mProximityCharsCorrectionEnabled;
@@ -219,6 +220,11 @@ public class Keyboard {
return code >= CODE_SPACE;
}
+ @Override
+ public String toString() {
+ return mId.toString();
+ }
+
public static class Params {
public KeyboardId mId;
public int mThemeId;
@@ -249,9 +255,9 @@ public class Keyboard {
public int GRID_WIDTH;
public int GRID_HEIGHT;
- public final HashSet mKeys = new HashSet();
- public final ArrayList mShiftKeys = new ArrayList();
- public final ArrayList mAltCodeKeysWhileTyping = new ArrayList();
+ public final HashSet mKeys = CollectionUtils.newHashSet();
+ public final ArrayList mShiftKeys = CollectionUtils.newArrayList();
+ public final ArrayList mAltCodeKeysWhileTyping = CollectionUtils.newArrayList();
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
public final KeyboardCodesSet mCodesSet = new KeyboardCodesSet();
public final KeyboardTextsSet mTextsSet = new KeyboardTextsSet();
@@ -278,9 +284,10 @@ public class Keyboard {
public void load(String[] data) {
final int dataLength = data.length;
if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
- if (LatinImeLogger.sDBG)
+ if (LatinImeLogger.sDBG) {
throw new RuntimeException(
"the size of touch position correction data is invalid");
+ }
return;
}
@@ -319,7 +326,7 @@ public class Keyboard {
public boolean isValid() {
return mEnabled && mXs != null && mYs != null && mRadii != null
- && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
+ && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
}
}
@@ -865,10 +872,12 @@ public class Keyboard {
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard);
try {
- if (a.hasValue(R.styleable.Keyboard_horizontalGap))
+ if (a.hasValue(R.styleable.Keyboard_horizontalGap)) {
throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap");
- if (a.hasValue(R.styleable.Keyboard_verticalGap))
+ }
+ if (a.hasValue(R.styleable.Keyboard_verticalGap)) {
throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap");
+ }
return new Row(mResources, mParams, parser, mCurrentY);
} finally {
a.recycle();
@@ -916,7 +925,9 @@ public class Keyboard {
throws XmlPullParserException, IOException {
if (skip) {
XmlParseUtils.checkEndTag(TAG_KEY, parser);
- if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY);
+ if (DEBUG) {
+ startEndTag("<%s /> skipped", TAG_KEY);
+ }
} else {
final Key key = new Key(mResources, mParams, row, parser);
if (DEBUG) {
@@ -1094,9 +1105,9 @@ public class Keyboard {
private boolean parseCaseCondition(XmlPullParser parser) {
final KeyboardId id = mParams.mId;
- if (id == null)
+ if (id == null) {
return true;
-
+ }
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard_Case);
try {
@@ -1200,9 +1211,9 @@ public class Keyboard {
// If does not have "index" attribute, that means this is wild-card for
// the attribute.
final TypedValue v = a.peekValue(index);
- if (v == null)
+ if (v == null) {
return true;
-
+ }
if (isIntegerValue(v)) {
return intValue == a.getInt(index, 0);
} else if (isStringValue(v)) {
@@ -1213,8 +1224,9 @@ public class Keyboard {
private static boolean stringArrayContains(String[] array, String value) {
for (final String elem : array) {
- if (elem.equals(value))
+ if (elem.equals(value)) {
return true;
+ }
}
return false;
}
@@ -1237,16 +1249,18 @@ public class Keyboard {
TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard_Key);
try {
- if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
+ if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) {
throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE
+ "/> needs styleName attribute", parser);
+ }
if (DEBUG) {
startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE,
- keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName),
- skip ? " skipped" : "");
+ keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName),
+ skip ? " skipped" : "");
}
- if (!skip)
+ if (!skip) {
mParams.mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
+ }
} finally {
keyStyleAttr.recycle();
keyAttrs.recycle();
@@ -1267,8 +1281,9 @@ public class Keyboard {
}
private void endRow(Row row) {
- if (mCurrentRow == null)
+ if (mCurrentRow == null) {
throw new InflateException("orphan end row tag");
+ }
if (mRightEdgeKey != null) {
mRightEdgeKey.markAsRightEdge(mParams);
mRightEdgeKey = null;
@@ -1304,8 +1319,9 @@ public class Keyboard {
public static float getDimensionOrFraction(TypedArray a, int index, int base,
float defValue) {
final TypedValue value = a.peekValue(index);
- if (value == null)
+ if (value == null) {
return defValue;
+ }
if (isFractionValue(value)) {
return a.getFraction(index, base, base, defValue);
} else if (isDimensionValue(value)) {
@@ -1316,8 +1332,9 @@ public class Keyboard {
public static int getEnumValue(TypedArray a, int index, int defValue) {
final TypedValue value = a.peekValue(index);
- if (value == null)
+ if (value == null) {
return defValue;
+ }
if (isIntegerValue(value)) {
return a.getInt(index, defValue);
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index b1621a55b..5c8f78f5e 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.keyboard;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.InputPointers;
public interface KeyboardActionListener {
@@ -44,21 +45,16 @@ public interface KeyboardActionListener {
*
* @param primaryCode this is the code of the key that was pressed
* @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by
- * {@link PointerTracker} or so, the value should be {@link #NOT_A_TOUCH_COORDINATE}.
- * If it's called on insertion from the suggestion strip, it should be
- * {@link #SUGGESTION_STRIP_COORDINATE}.
+ * {@link PointerTracker} or so, the value should be
+ * {@link Constants#NOT_A_COORDINATE}. If it's called on insertion from the
+ * suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}.
* @param y y-coordinate pixel of touched event. If {@link #onCodeInput} is not called by
- * {@link PointerTracker} or so, the value should be {@link #NOT_A_TOUCH_COORDINATE}.
- * If it's called on insertion from the suggestion strip, it should be
- * {@link #SUGGESTION_STRIP_COORDINATE}.
+ * {@link PointerTracker} or so, the value should be
+ * {@link Constants#NOT_A_COORDINATE}.If it's called on insertion from the
+ * suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}.
*/
public void onCodeInput(int primaryCode, int x, int y);
- // See {@link Adapter#isInvalidCoordinate(int)}.
- public static final int NOT_A_TOUCH_COORDINATE = -1;
- public static final int SUGGESTION_STRIP_COORDINATE = -2;
- public static final int SPELL_CHECKER_COORDINATE = -3;
-
/**
* Sends a sequence of characters to the listener.
*
@@ -119,9 +115,9 @@ public interface KeyboardActionListener {
// TODO: Remove this method when the vertical correction is removed.
public static boolean isInvalidCoordinate(int coordinate) {
- // Detect {@link KeyboardActionListener#NOT_A_TOUCH_COORDINATE},
- // {@link KeyboardActionListener#SUGGESTION_STRIP_COORDINATE}, and
- // {@link KeyboardActionListener#SPELL_CHECKER_COORDINATE}.
+ // Detect {@link Constants#NOT_A_COORDINATE},
+ // {@link Constants#SUGGESTION_STRIP_COORDINATE}, and
+ // {@link Constants#SPELL_CHECKER_COORDINATE}.
return coordinate < 0;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 64b3f0952..76ac3de22 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -36,6 +36,7 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
import com.android.inputmethod.keyboard.KeyboardLayoutSet.Params.ElementParams;
+import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.InputAttributes;
import com.android.inputmethod.latin.InputTypeUtils;
import com.android.inputmethod.latin.LatinImeLogger;
@@ -71,7 +72,7 @@ public class KeyboardLayoutSet {
private final Params mParams;
private static final HashMap> sKeyboardCache =
- new HashMap>();
+ CollectionUtils.newHashMap();
private static final KeysCache sKeysCache = new KeysCache();
public static class KeyboardLayoutSetException extends RuntimeException {
@@ -84,11 +85,7 @@ public class KeyboardLayoutSet {
}
public static class KeysCache {
- private final HashMap mMap;
-
- public KeysCache() {
- mMap = new HashMap();
- }
+ private final HashMap mMap = CollectionUtils.newHashMap();
public void clear() {
mMap.clear();
@@ -120,7 +117,7 @@ public class KeyboardLayoutSet {
int mWidth;
// Sparse array of KeyboardLayoutSet element parameters indexed by element's id.
final SparseArray mKeyboardLayoutSetElementIdToParamsMap =
- new SparseArray();
+ CollectionUtils.newSparseArray();
static class ElementParams {
int mKeyboardXmlId;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 10f651ad1..fd789f029 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -21,7 +21,6 @@ import android.content.SharedPreferences;
import android.content.res.Resources;
import android.util.Log;
import android.view.ContextThemeWrapper;
-import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
@@ -38,7 +37,7 @@ import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SettingsValues;
import com.android.inputmethod.latin.SubtypeSwitcher;
-import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.WordComposer;
public class KeyboardSwitcher implements KeyboardState.SwitchActions {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
@@ -46,24 +45,24 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions {
public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916";
static class KeyboardTheme {
- public final String mName;
public final int mThemeId;
public final int mStyleId;
- public KeyboardTheme(String name, int themeId, int styleId) {
- mName = name;
+ // Note: The themeId should be aligned with "themeId" attribute of Keyboard style
+ // in values/style.xml.
+ public KeyboardTheme(int themeId, int styleId) {
mThemeId = themeId;
mStyleId = styleId;
}
}
private static final KeyboardTheme[] KEYBOARD_THEMES = {
- new KeyboardTheme("Basic", 0, R.style.KeyboardTheme),
- new KeyboardTheme("HighContrast", 1, R.style.KeyboardTheme_HighContrast),
- new KeyboardTheme("Stone", 6, R.style.KeyboardTheme_Stone),
- new KeyboardTheme("Stone.Bold", 7, R.style.KeyboardTheme_Stone_Bold),
- new KeyboardTheme("GingerBread", 8, R.style.KeyboardTheme_Gingerbread),
- new KeyboardTheme("IceCreamSandwich", 5, R.style.KeyboardTheme_IceCreamSandwich),
+ new KeyboardTheme(0, R.style.KeyboardTheme),
+ new KeyboardTheme(1, R.style.KeyboardTheme_HighContrast),
+ new KeyboardTheme(6, R.style.KeyboardTheme_Stone),
+ new KeyboardTheme(7, R.style.KeyboardTheme_Stone_Bold),
+ new KeyboardTheme(8, R.style.KeyboardTheme_Gingerbread),
+ new KeyboardTheme(5, R.style.KeyboardTheme_IceCreamSandwich),
};
private SubtypeSwitcher mSubtypeSwitcher;
@@ -354,22 +353,9 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions {
mKeyboardView.closing();
}
- Utils.GCUtils.getInstance().reset();
- boolean tryGC = true;
- for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
- try {
- setContextThemeWrapper(mLatinIME, mKeyboardTheme);
- mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
- R.layout.input_view, null);
- tryGC = false;
- } catch (OutOfMemoryError e) {
- Log.w(TAG, "load keyboard failed: " + e);
- tryGC = Utils.GCUtils.getInstance().tryGCOrWait(mKeyboardTheme.mName, e);
- } catch (InflateException e) {
- Log.w(TAG, "load keyboard failed: " + e);
- tryGC = Utils.GCUtils.getInstance().tryGCOrWait(mKeyboardTheme.mName, e);
- }
- }
+ setContextThemeWrapper(mLatinIME, mKeyboardTheme);
+ mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
+ R.layout.input_view, null);
mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
if (isHardwareAcceleratedDrawingEnabled) {
@@ -402,4 +388,16 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
}
}
+
+ public int getManualCapsMode() {
+ switch (getKeyboard().mId.mElementId) {
+ case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
+ case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
+ return WordComposer.CAPS_MODE_MANUAL_SHIFT_LOCKED;
+ case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
+ return WordComposer.CAPS_MODE_MANUAL_SHIFTED;
+ default:
+ return WordComposer.CAPS_MODE_OFF;
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 0e6de7032..127ac7160 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -30,6 +30,7 @@ import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Message;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -38,6 +39,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.android.inputmethod.keyboard.internal.PreviewPlacerView;
+import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
@@ -78,8 +80,12 @@ import java.util.HashSet;
* @attr ref R.styleable#KeyboardView_shadowRadius
*/
public class KeyboardView extends View implements PointerTracker.DrawingProxy {
+ private static final String TAG = KeyboardView.class.getSimpleName();
+
// Miscellaneous constants
private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable };
+ private static final float UNDEFINED_RATIO = -1.0f;
+ private static final int UNDEFINED_DIMENSION = -1;
// XML attributes
protected final float mVerticalCorrection;
@@ -103,23 +109,19 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Key preview
private final int mKeyPreviewLayoutId;
+ private final SparseArray mKeyPreviewTexts = CollectionUtils.newSparseArray();
protected final KeyPreviewDrawParams mKeyPreviewDrawParams;
private boolean mShowKeyPreviewPopup = true;
private int mDelayAfterPreview;
private final PreviewPlacerView mPreviewPlacerView;
- /** True if {@link KeyboardView} should handle gesture events. */
- protected boolean mShouldHandleGesture;
-
// Drawing
/** True if the entire keyboard needs to be dimmed. */
private boolean mNeedsToDimEntireKeyboard;
- /** Whether the keyboard bitmap buffer needs to be redrawn before it's blitted. **/
- private boolean mBufferNeedsUpdate;
/** True if all keys should be drawn */
private boolean mInvalidateAllKeys;
/** The keys that should be drawn */
- private final HashSet mInvalidatedKeys = new HashSet();
+ private final HashSet mInvalidatedKeys = CollectionUtils.newHashSet();
/** The working rectangle variable */
private final Rect mWorkingRect = new Rect();
/** The keyboard bitmap buffer for faster updates */
@@ -131,9 +133,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
private final Paint mPaint = new Paint();
private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics();
// This sparse array caches key label text height in pixel indexed by key label text size.
- private static final SparseArray sTextHeightCache = new SparseArray();
+ private static final SparseArray sTextHeightCache = CollectionUtils.newSparseArray();
// This sparse array caches key label text width in pixel indexed by key label text size.
- private static final SparseArray sTextWidthCache = new SparseArray();
+ private static final SparseArray sTextWidthCache = CollectionUtils.newSparseArray();
private static final char[] KEY_LABEL_REFERENCE_CHAR = { 'M' };
private static final char[] KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR = { '8' };
@@ -153,7 +155,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
final PointerTracker tracker = (PointerTracker) msg.obj;
switch (msg.what) {
case MSG_DISMISS_KEY_PREVIEW:
- tracker.getKeyPreviewText().setVisibility(View.INVISIBLE);
+ final TextView previewText = keyboardView.mKeyPreviewTexts.get(tracker.mPointerId);
+ if (previewText != null) {
+ previewText.setVisibility(INVISIBLE);
+ }
break;
}
}
@@ -166,7 +171,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
removeMessages(MSG_DISMISS_KEY_PREVIEW, tracker);
}
- public void cancelAllDismissKeyPreviews() {
+ private void cancelAllDismissKeyPreviews() {
removeMessages(MSG_DISMISS_KEY_PREVIEW);
}
@@ -199,7 +204,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
private final float mKeyHintLetterRatio;
private final float mKeyShiftedLetterHintRatio;
private final float mKeyHintLabelRatio;
- private static final float UNDEFINED_RATIO = -1.0f;
public final Rect mPadding = new Rect();
public int mKeyLetterSize;
@@ -211,26 +215,22 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
public int mKeyHintLabelSize;
public int mAnimAlpha;
- public KeyDrawParams(TypedArray a) {
+ public KeyDrawParams(final TypedArray a) {
mKeyBackground = a.getDrawable(R.styleable.KeyboardView_keyBackground);
- if (a.hasValue(R.styleable.KeyboardView_keyLetterSize)) {
- mKeyLetterRatio = UNDEFINED_RATIO;
- mKeyLetterSize = a.getDimensionPixelSize(R.styleable.KeyboardView_keyLetterSize, 0);
- } else {
- mKeyLetterRatio = getRatio(a, R.styleable.KeyboardView_keyLetterRatio);
+ if (!isValidFraction(mKeyLetterRatio = getFraction(a,
+ R.styleable.KeyboardView_keyLetterSize))) {
+ mKeyLetterSize = getDimensionPixelSize(a, R.styleable.KeyboardView_keyLetterSize);
}
- if (a.hasValue(R.styleable.KeyboardView_keyLabelSize)) {
- mKeyLabelRatio = UNDEFINED_RATIO;
- mKeyLabelSize = a.getDimensionPixelSize(R.styleable.KeyboardView_keyLabelSize, 0);
- } else {
- mKeyLabelRatio = getRatio(a, R.styleable.KeyboardView_keyLabelRatio);
+ if (!isValidFraction(mKeyLabelRatio = getFraction(a,
+ R.styleable.KeyboardView_keyLabelSize))) {
+ mKeyLabelSize = getDimensionPixelSize(a, R.styleable.KeyboardView_keyLabelSize);
}
- mKeyLargeLabelRatio = getRatio(a, R.styleable.KeyboardView_keyLargeLabelRatio);
- mKeyLargeLetterRatio = getRatio(a, R.styleable.KeyboardView_keyLargeLetterRatio);
- mKeyHintLetterRatio = getRatio(a, R.styleable.KeyboardView_keyHintLetterRatio);
- mKeyShiftedLetterHintRatio = getRatio(a,
+ mKeyLargeLabelRatio = getFraction(a, R.styleable.KeyboardView_keyLargeLabelRatio);
+ mKeyLargeLetterRatio = getFraction(a, R.styleable.KeyboardView_keyLargeLetterRatio);
+ mKeyHintLetterRatio = getFraction(a, R.styleable.KeyboardView_keyHintLetterRatio);
+ mKeyShiftedLetterHintRatio = getFraction(a,
R.styleable.KeyboardView_keyShiftedLetterHintRatio);
- mKeyHintLabelRatio = getRatio(a, R.styleable.KeyboardView_keyHintLabelRatio);
+ mKeyHintLabelRatio = getFraction(a, R.styleable.KeyboardView_keyHintLabelRatio);
mKeyLabelHorizontalPadding = a.getDimension(
R.styleable.KeyboardView_keyLabelHorizontalPadding, 0);
mKeyHintLetterPadding = a.getDimension(
@@ -257,10 +257,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
public void updateKeyHeight(int keyHeight) {
- if (mKeyLetterRatio >= 0.0f) {
+ if (isValidFraction(mKeyLetterRatio)) {
mKeyLetterSize = (int)(keyHeight * mKeyLetterRatio);
}
- if (mKeyLabelRatio >= 0.0f) {
+ if (isValidFraction(mKeyLabelRatio)) {
mKeyLabelSize = (int)(keyHeight * mKeyLabelRatio);
}
mKeyLargeLabelSize = (int)(keyHeight * mKeyLargeLabelRatio);
@@ -335,7 +335,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
R.styleable.KeyboardView_keyPreviewOffset, 0);
mPreviewHeight = a.getDimensionPixelSize(
R.styleable.KeyboardView_keyPreviewHeight, 80);
- mPreviewTextRatio = getRatio(a, R.styleable.KeyboardView_keyPreviewTextRatio);
+ mPreviewTextRatio = getFraction(a, R.styleable.KeyboardView_keyPreviewTextRatio);
mPreviewTextColor = a.getColor(R.styleable.KeyboardView_keyPreviewTextColor, 0);
mLingerTimeout = a.getInt(R.styleable.KeyboardView_keyPreviewLingerTimeout, 0);
@@ -367,9 +367,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
-
mKeyDrawParams = new KeyDrawParams(a);
mKeyPreviewDrawParams = new KeyPreviewDrawParams(a, mKeyDrawParams);
+ mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout;
mKeyPreviewLayoutId = a.getResourceId(R.styleable.KeyboardView_keyPreviewLayout, 0);
if (mKeyPreviewLayoutId == 0) {
mShowKeyPreviewPopup = false;
@@ -378,17 +378,30 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
R.styleable.KeyboardView_verticalCorrection, 0);
mMoreKeysLayout = a.getResourceId(R.styleable.KeyboardView_moreKeysLayout, 0);
mBackgroundDimAlpha = a.getInt(R.styleable.KeyboardView_backgroundDimAlpha, 0);
- mPreviewPlacerView = new PreviewPlacerView(context, a);
a.recycle();
- mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout;
-
+ mPreviewPlacerView = new PreviewPlacerView(context, attrs);
mPaint.setAntiAlias(true);
}
- // Read fraction value in TypedArray as float.
- /* package */ static float getRatio(TypedArray a, int index) {
- return a.getFraction(index, 1000, 1000, 1) / 1000.0f;
+ static boolean isValidFraction(final float fraction) {
+ return fraction >= 0.0f;
+ }
+
+ static float getFraction(final TypedArray a, final int index) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null || value.type != TypedValue.TYPE_FRACTION) {
+ return UNDEFINED_RATIO;
+ }
+ return a.getFraction(index, 1, 1, UNDEFINED_RATIO);
+ }
+
+ public static int getDimensionPixelSize(final TypedArray a, final int index) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null || value.type != TypedValue.TYPE_DIMENSION) {
+ return UNDEFINED_DIMENSION;
+ }
+ return a.getDimensionPixelSize(index, UNDEFINED_DIMENSION);
}
/**
@@ -438,9 +451,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
return mShowKeyPreviewPopup;
}
- public void setGestureHandlingMode(boolean shouldHandleGesture,
- boolean drawsGesturePreviewTrail, boolean drawsGestureFloatingPreviewText) {
- mShouldHandleGesture = shouldHandleGesture;
+ public void setGesturePreviewMode(boolean drawsGesturePreviewTrail,
+ boolean drawsGestureFloatingPreviewText) {
mPreviewPlacerView.setGesturePreviewMode(
drawsGesturePreviewTrail, drawsGestureFloatingPreviewText);
}
@@ -463,16 +475,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
onDrawKeyboard(canvas);
return;
}
- if (mBufferNeedsUpdate || mOffscreenBuffer == null) {
- mBufferNeedsUpdate = false;
+
+ final boolean bufferNeedsUpdates = mInvalidateAllKeys || !mInvalidatedKeys.isEmpty();
+ if (bufferNeedsUpdates || mOffscreenBuffer == null) {
if (maybeAllocateOffscreenBuffer()) {
mInvalidateAllKeys = true;
- // TODO: Stop using the offscreen canvas even when in software rendering
- if (mOffscreenCanvas != null) {
- mOffscreenCanvas.setBitmap(mOffscreenBuffer);
- } else {
- mOffscreenCanvas = new Canvas(mOffscreenBuffer);
- }
+ maybeCreateOffscreenCanvas();
}
onDrawKeyboard(mOffscreenCanvas);
}
@@ -501,6 +509,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
+ private void maybeCreateOffscreenCanvas() {
+ // TODO: Stop using the offscreen canvas even when in software rendering
+ if (mOffscreenCanvas != null) {
+ mOffscreenCanvas.setBitmap(mOffscreenBuffer);
+ } else {
+ mOffscreenCanvas = new Canvas(mOffscreenBuffer);
+ }
+ }
+
private void onDrawKeyboard(final Canvas canvas) {
if (mKeyboard == null) return;
@@ -528,13 +545,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
if (!isHardwareAccelerated) {
canvas.clipRegion(mClipRegion, Region.Op.REPLACE);
- }
-
- // Draw keyboard background.
- canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
- final Drawable background = getBackground();
- if (background != null) {
- background.draw(canvas);
+ // Draw keyboard background.
+ canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
+ final Drawable background = getBackground();
+ if (background != null) {
+ background.draw(canvas);
+ }
}
// TODO: Confirm if it's really required to draw all keys when hardware acceleration is on.
@@ -907,15 +923,30 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- // Called by {@link PointerTracker} constructor to create a TextView.
- @Override
- public TextView inflateKeyPreviewText() {
+ private TextView getKeyPreviewText(final int pointerId) {
+ TextView previewText = mKeyPreviewTexts.get(pointerId);
+ if (previewText != null) {
+ return previewText;
+ }
final Context context = getContext();
if (mKeyPreviewLayoutId != 0) {
- return (TextView)LayoutInflater.from(context).inflate(mKeyPreviewLayoutId, null);
+ previewText = (TextView)LayoutInflater.from(context).inflate(mKeyPreviewLayoutId, null);
} else {
- return new TextView(context);
+ previewText = new TextView(context);
}
+ mKeyPreviewTexts.put(pointerId, previewText);
+ return previewText;
+ }
+
+ private void dismissAllKeyPreviews() {
+ final int pointerCount = mKeyPreviewTexts.size();
+ for (int id = 0; id < pointerCount; id++) {
+ final TextView previewText = mKeyPreviewTexts.get(id);
+ if (previewText != null) {
+ previewText.setVisibility(INVISIBLE);
+ }
+ }
+ PointerTracker.setReleasedKeyGraphicsToAllKeys();
}
@Override
@@ -936,9 +967,18 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
final int[] viewOrigin = new int[2];
getLocationInWindow(viewOrigin);
mPreviewPlacerView.setOrigin(viewOrigin[0], viewOrigin[1]);
- final ViewGroup windowContentView =
- (ViewGroup)getRootView().findViewById(android.R.id.content);
- windowContentView.addView(mPreviewPlacerView);
+ final View rootView = getRootView();
+ if (rootView == null) {
+ Log.w(TAG, "Cannot find root view");
+ return;
+ }
+ final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content);
+ // Note: It'd be very weird if we get null by android.R.id.content.
+ if (windowContentView == null) {
+ Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView");
+ } else {
+ windowContentView.addView(mPreviewPlacerView);
+ }
}
public void showGestureFloatingPreviewText(String gestureFloatingPreviewText) {
@@ -952,7 +992,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
@Override
- public void showGestureTrail(PointerTracker tracker) {
+ public void showGesturePreviewTrail(PointerTracker tracker) {
locatePreviewPlacerView();
mPreviewPlacerView.invalidatePointer(tracker);
}
@@ -962,7 +1002,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
public void showKeyPreview(PointerTracker tracker) {
if (!mShowKeyPreviewPopup) return;
- final TextView previewText = tracker.getKeyPreviewText();
+ final TextView previewText = getKeyPreviewText(tracker.mPointerId);
// If the key preview has no parent view yet, add it to the ViewGroup which can place
// key preview absolutely in SoftInputWindow.
if (previewText.getParent() == null) {
@@ -1052,7 +1092,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
public void invalidateAllKeys() {
mInvalidatedKeys.clear();
mInvalidateAllKeys = true;
- mBufferNeedsUpdate = true;
invalidate();
}
@@ -1070,13 +1109,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
mInvalidatedKeys.add(key);
final int x = key.mX + getPaddingLeft();
final int y = key.mY + getPaddingTop();
- mWorkingRect.set(x, y, x + key.mWidth, y + key.mHeight);
- mBufferNeedsUpdate = true;
- invalidate(mWorkingRect);
+ invalidate(x, y, x + key.mWidth, y + key.mHeight);
}
public void closing() {
- PointerTracker.dismissAllKeyPreviews();
+ dismissAllKeyPreviews();
cancelAllMessages();
mInvalidateAllKeys = true;
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index fe9cb9415..df84271e8 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -110,7 +110,6 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
new WeakHashMap();
private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
- private final PointerTrackerParams mPointerTrackerParams;
private final SuddenJumpingTouchEventHandler mTouchScreenRegulator;
protected KeyDetector mKeyDetector;
@@ -127,11 +126,26 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
private static final int MSG_LONGPRESS_KEY = 2;
private static final int MSG_DOUBLE_TAP = 3;
- private final KeyTimerParams mParams;
+ private final int mKeyRepeatStartTimeout;
+ private final int mKeyRepeatInterval;
+ private final int mLongPressKeyTimeout;
+ private final int mLongPressShiftKeyTimeout;
+ private final int mIgnoreAltCodeKeyTimeout;
- public KeyTimerHandler(MainKeyboardView outerInstance, KeyTimerParams params) {
+ public KeyTimerHandler(final MainKeyboardView outerInstance,
+ final TypedArray mainKeyboardViewAttr) {
super(outerInstance);
- mParams = params;
+
+ mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0);
+ mKeyRepeatInterval = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_keyRepeatInterval, 0);
+ mLongPressKeyTimeout = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_longPressKeyTimeout, 0);
+ mLongPressShiftKeyTimeout = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_longPressShiftKeyTimeout, 0);
+ mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
}
@Override
@@ -146,7 +160,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
final Key currentKey = tracker.getKey();
if (currentKey != null && currentKey.mCode == msg.arg1) {
tracker.onRegisterKey(currentKey);
- startKeyRepeatTimer(tracker, mParams.mKeyRepeatInterval);
+ startKeyRepeatTimer(tracker, mKeyRepeatInterval);
}
break;
case MSG_LONGPRESS_KEY:
@@ -167,7 +181,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
@Override
public void startKeyRepeatTimer(PointerTracker tracker) {
- startKeyRepeatTimer(tracker, mParams.mKeyRepeatStartTimeout);
+ startKeyRepeatTimer(tracker, mKeyRepeatStartTimeout);
}
public void cancelKeyRepeatTimer() {
@@ -185,7 +199,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
final int delay;
switch (code) {
case Keyboard.CODE_SHIFT:
- delay = mParams.mLongPressShiftKeyTimeout;
+ delay = mLongPressShiftKeyTimeout;
break;
default:
delay = 0;
@@ -206,15 +220,15 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
final int delay;
switch (key.mCode) {
case Keyboard.CODE_SHIFT:
- delay = mParams.mLongPressShiftKeyTimeout;
+ delay = mLongPressShiftKeyTimeout;
break;
default:
if (KeyboardSwitcher.getInstance().isInMomentarySwitchState()) {
// We use longer timeout for sliding finger input started from the symbols
// mode key.
- delay = mParams.mLongPressKeyTimeout * 3;
+ delay = mLongPressKeyTimeout * 3;
} else {
- delay = mParams.mLongPressKeyTimeout;
+ delay = mLongPressKeyTimeout;
}
break;
}
@@ -268,7 +282,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
}
sendMessageDelayed(
- obtainMessage(MSG_TYPING_STATE_EXPIRED), mParams.mIgnoreAltCodeKeyTimeout);
+ obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout);
if (isTyping) {
return;
}
@@ -307,50 +321,6 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
}
}
- public static class PointerTrackerParams {
- public final boolean mSlidingKeyInputEnabled;
- public final int mTouchNoiseThresholdTime;
- public final float mTouchNoiseThresholdDistance;
-
- public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();
-
- private PointerTrackerParams() {
- mSlidingKeyInputEnabled = false;
- mTouchNoiseThresholdTime =0;
- mTouchNoiseThresholdDistance = 0;
- }
-
- public PointerTrackerParams(TypedArray mainKeyboardViewAttr) {
- mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean(
- R.styleable.MainKeyboardView_slidingKeyInputEnable, false);
- mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0);
- mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimension(
- R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0);
- }
- }
-
- static class KeyTimerParams {
- public final int mKeyRepeatStartTimeout;
- public final int mKeyRepeatInterval;
- public final int mLongPressKeyTimeout;
- public final int mLongPressShiftKeyTimeout;
- public final int mIgnoreAltCodeKeyTimeout;
-
- public KeyTimerParams(TypedArray mainKeyboardViewAttr) {
- mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0);
- mKeyRepeatInterval = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_keyRepeatInterval, 0);
- mLongPressKeyTimeout = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_longPressKeyTimeout, 0);
- mLongPressShiftKeyTimeout = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_longPressShiftKeyTimeout, 0);
- mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
- }
- }
-
public MainKeyboardView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.mainKeyboardViewStyle);
}
@@ -374,8 +344,8 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false);
mAutoCorrectionSpacebarLedIcon = a.getDrawable(
R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon);
- mSpacebarTextRatio = a.getFraction(R.styleable.MainKeyboardView_spacebarTextRatio,
- 1000, 1000, 1) / 1000.0f;
+ mSpacebarTextRatio = a.getFraction(
+ R.styleable.MainKeyboardView_spacebarTextRatio, 1, 1, 1.0f);
mSpacebarTextColor = a.getColor(R.styleable.MainKeyboardView_spacebarTextColor, 0);
mSpacebarTextShadowColor = a.getColor(
R.styleable.MainKeyboardView_spacebarTextShadowColor, 0);
@@ -389,19 +359,15 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
final int altCodeKeyWhileTypingFadeinAnimatorResId = a.getResourceId(
R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0);
- final KeyTimerParams keyTimerParams = new KeyTimerParams(a);
- mPointerTrackerParams = new PointerTrackerParams(a);
-
final float keyHysteresisDistance = a.getDimension(
R.styleable.MainKeyboardView_keyHysteresisDistance, 0);
mKeyDetector = new KeyDetector(keyHysteresisDistance);
- mKeyTimerHandler = new KeyTimerHandler(this, keyTimerParams);
+ mKeyTimerHandler = new KeyTimerHandler(this, a);
mConfigShowMoreKeysKeyboardAtTouchedPoint = a.getBoolean(
R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false);
+ PointerTracker.setParameters(a);
a.recycle();
- PointerTracker.setParameters(mPointerTrackerParams);
-
mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator(
languageOnSpacebarFadeoutAnimatorResId, this);
mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator(
@@ -482,7 +448,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
super.setKeyboard(keyboard);
mKeyDetector.setKeyboard(
keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection);
- PointerTracker.setKeyDetector(mKeyDetector, mShouldHandleGesture);
+ PointerTracker.setKeyDetector(mKeyDetector);
mTouchScreenRegulator.setKeyboard(keyboard);
mMoreKeysPanelCache.clear();
@@ -500,12 +466,13 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard);
}
- @Override
- public void setGestureHandlingMode(final boolean shouldHandleGesture,
- boolean drawsGesturePreviewTrail, boolean drawsGestureFloatingPreviewText) {
- super.setGestureHandlingMode(shouldHandleGesture, drawsGesturePreviewTrail,
- drawsGestureFloatingPreviewText);
- PointerTracker.setKeyDetector(mKeyDetector, shouldHandleGesture);
+ // Note that this method is called from a non-UI thread.
+ public void setMainDictionaryAvailability(boolean mainDictionaryAvailable) {
+ PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable);
+ }
+
+ public void setGestureHandlingEnabledByUser(boolean gestureHandlingEnabledByUser) {
+ PointerTracker.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser);
}
/**
@@ -527,7 +494,17 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
// to properly show the splash screen, which requires that the window token of the
// KeyboardView be non-null.
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow();
+ ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(this);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ // Notify the research logger that the keyboard view has been detached. This is needed
+ // to invalidate the reference of {@link MainKeyboardView} to null.
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.getInstance().mainKeyboardView_onDetachedFromWindow();
}
}
@@ -607,9 +584,8 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
}
private void invokeCodeInput(int primaryCode) {
- mKeyboardActionListener.onCodeInput(primaryCode,
- KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
- KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
+ mKeyboardActionListener.onCodeInput(
+ primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
private void invokeReleaseKey(int primaryCode) {
@@ -834,20 +810,6 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
return false;
}
- @Override
- public void draw(Canvas c) {
- Utils.GCUtils.getInstance().reset();
- boolean tryGC = true;
- for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
- try {
- super.draw(c);
- tryGC = false;
- } catch (OutOfMemoryError e) {
- tryGC = Utils.GCUtils.getInstance().tryGCOrWait(TAG, e);
- }
- }
- }
-
/**
* Receives hover events from the input framework.
*
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
index a183546dd..cd4e3001e 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
@@ -39,11 +39,7 @@ public class MoreKeysDetector extends KeyDetector {
Key nearestKey = null;
int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
- final Keyboard keyboard = getKeyboard();
- if (keyboard == null) {
- throw new NullPointerException("Keyboard isn't set");
- }
- for (final Key key : keyboard.mKeys) {
+ for (final Key key : getKeyboard().mKeys) {
final int dist = key.squaredDistanceToEdge(touchX, touchY);
if (dist < nearestDist) {
nearestKey = key;
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index 870eff29f..e513a1477 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -25,6 +25,7 @@ import android.widget.PopupWindow;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.R;
@@ -50,7 +51,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
public void onCodeInput(int primaryCode, int x, int y) {
// Because a more keys keyboard doesn't need proximity characters correction, we don't
// send touch event coordinates.
- mListener.onCodeInput(primaryCode, NOT_A_TOUCH_COORDINATE, NOT_A_TOUCH_COORDINATE);
+ mListener.onCodeInput(
+ primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
@Override
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 184011ffe..be101cfb0 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -16,25 +16,25 @@
package com.android.inputmethod.keyboard;
-import android.graphics.Canvas;
-import android.graphics.Paint;
+import android.content.res.TypedArray;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
-import android.view.View;
-import android.widget.TextView;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.keyboard.internal.GestureStroke;
+import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewTrail;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
+import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.research.ResearchLogger;
import java.util.ArrayList;
-public class PointerTracker implements PointerTrackerQueue.ElementActions {
+public class PointerTracker implements PointerTrackerQueue.Element {
private static final String TAG = PointerTracker.class.getSimpleName();
private static final boolean DEBUG_EVENT = false;
private static final boolean DEBUG_MOVE_EVENT = false;
@@ -43,6 +43,9 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
/** True if {@link PointerTracker}s should handle gesture events. */
private static boolean sShouldHandleGesture = false;
+ private static boolean sMainDictionaryAvailable = false;
+ private static boolean sGestureHandlingEnabledByInputField = false;
+ private static boolean sGestureHandlingEnabledByUser = false;
private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec
@@ -75,10 +78,9 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
public interface DrawingProxy extends MoreKeysPanel.Controller {
public void invalidateKey(Key key);
- public TextView inflateKeyPreviewText();
public void showKeyPreview(PointerTracker tracker);
public void dismissKeyPreview(PointerTracker tracker);
- public void showGestureTrail(PointerTracker tracker);
+ public void showGesturePreviewTrail(PointerTracker tracker);
}
public interface TimerProxy {
@@ -117,19 +119,40 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
+ static class PointerTrackerParams {
+ public final boolean mSlidingKeyInputEnabled;
+ public final int mTouchNoiseThresholdTime;
+ public final float mTouchNoiseThresholdDistance;
+ public final int mTouchNoiseThresholdDistanceSquared;
+
+ public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();
+
+ private PointerTrackerParams() {
+ mSlidingKeyInputEnabled = false;
+ mTouchNoiseThresholdTime = 0;
+ mTouchNoiseThresholdDistance = 0.0f;
+ mTouchNoiseThresholdDistanceSquared = 0;
+ }
+
+ public PointerTrackerParams(TypedArray mainKeyboardViewAttr) {
+ mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean(
+ R.styleable.MainKeyboardView_slidingKeyInputEnable, false);
+ mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0);
+ final float touchNouseThresholdDistance = mainKeyboardViewAttr.getDimension(
+ R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0);
+ mTouchNoiseThresholdDistance = touchNouseThresholdDistance;
+ mTouchNoiseThresholdDistanceSquared =
+ (int)(touchNouseThresholdDistance * touchNouseThresholdDistance);
+ }
+ }
+
// Parameters for pointer handling.
- private static MainKeyboardView.PointerTrackerParams sParams;
- private static int sTouchNoiseThresholdDistanceSquared;
+ private static PointerTrackerParams sParams;
private static boolean sNeedsPhantomSuddenMoveEventHack;
- private static final ArrayList sTrackers = new ArrayList();
- private static final InputPointers sAggregratedPointers = new InputPointers(
- GestureStroke.DEFAULT_CAPACITY);
+ private static final ArrayList sTrackers = CollectionUtils.newArrayList();
private static PointerTrackerQueue sPointerTrackerQueue;
- // HACK: Change gesture detection criteria depending on this variable.
- // TODO: Find more comprehensive ways to detect a gesture start.
- // True when the previous user input was a gesture input, not a typing input.
- private static boolean sWasInGesture;
public final int mPointerId;
@@ -140,15 +163,14 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
private Keyboard mKeyboard;
private int mKeyQuarterWidthSquared;
- private final TextView mKeyPreviewText;
- private boolean mIsAlphabetKeyboard;
- private boolean mIsPossibleGesture = false;
- private boolean mInGesture = false;
-
- // TODO: Remove these variables
- private int mLastRecognitionPointSize = 0;
- private long mLastRecognitionTime = 0;
+ private boolean mIsDetectingGesture = false; // per PointerTracker.
+ private static boolean sInGesture = false;
+ private static long sGestureFirstDownTime;
+ private static final InputPointers sAggregratedPointers = new InputPointers(
+ GestureStroke.DEFAULT_CAPACITY);
+ private static int sLastRecognitionPointSize = 0;
+ private static long sLastRecognitionTime = 0;
// The position and time at which first down event occurred.
private long mDownTime;
@@ -186,7 +208,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
private static final KeyboardActionListener EMPTY_LISTENER =
new KeyboardActionListener.Adapter();
- private final GestureStroke mGestureStroke;
+ private final GestureStrokeWithPreviewTrail mGestureStrokeWithPreviewTrail;
public static void init(boolean hasDistinctMultitouch,
boolean needsPhantomSuddenMoveEventHack) {
@@ -196,28 +218,32 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
sPointerTrackerQueue = null;
}
sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
-
- setParameters(MainKeyboardView.PointerTrackerParams.DEFAULT);
- updateGestureHandlingMode(null, false /* shouldHandleGesture */);
+ sParams = PointerTrackerParams.DEFAULT;
}
- public static void setParameters(MainKeyboardView.PointerTrackerParams params) {
- sParams = params;
- sTouchNoiseThresholdDistanceSquared = (int)(
- params.mTouchNoiseThresholdDistance * params.mTouchNoiseThresholdDistance);
+ public static void setParameters(final TypedArray mainKeyboardViewAttr) {
+ sParams = new PointerTrackerParams(mainKeyboardViewAttr);
}
- private static void updateGestureHandlingMode(Keyboard keyboard, boolean shouldHandleGesture) {
- if (!shouldHandleGesture
- || AccessibilityUtils.getInstance().isTouchExplorationEnabled()
- || (keyboard != null && keyboard.mId.passwordInput())) {
- sShouldHandleGesture = false;
- } else {
- sShouldHandleGesture = true;
- }
+ private static void updateGestureHandlingMode() {
+ sShouldHandleGesture = sMainDictionaryAvailable
+ && sGestureHandlingEnabledByInputField
+ && sGestureHandlingEnabledByUser
+ && !AccessibilityUtils.getInstance().isTouchExplorationEnabled();
}
- public static PointerTracker getPointerTracker(final int id, KeyEventHandler handler) {
+ // Note that this method is called from a non-UI thread.
+ public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) {
+ sMainDictionaryAvailable = mainDictionaryAvailable;
+ updateGestureHandlingMode();
+ }
+
+ public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) {
+ sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser;
+ updateGestureHandlingMode();
+ }
+
+ public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) {
final ArrayList trackers = sTrackers;
// Create pointer trackers until we can get 'id+1'-th tracker, if needed.
@@ -233,7 +259,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false;
}
- public static void setKeyboardActionListener(KeyboardActionListener listener) {
+ public static void setKeyboardActionListener(final KeyboardActionListener listener) {
final int trackersSize = sTrackers.size();
for (int i = 0; i < trackersSize; ++i) {
final PointerTracker tracker = sTrackers.get(i);
@@ -241,7 +267,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- public static void setKeyDetector(KeyDetector keyDetector, boolean shouldHandleGesture) {
+ public static void setKeyDetector(final KeyDetector keyDetector) {
final int trackersSize = sTrackers.size();
for (int i = 0; i < trackersSize; ++i) {
final PointerTracker tracker = sTrackers.get(i);
@@ -250,70 +276,33 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
tracker.mKeyboardLayoutHasBeenChanged = true;
}
final Keyboard keyboard = keyDetector.getKeyboard();
- updateGestureHandlingMode(keyboard, shouldHandleGesture);
+ sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput();
+ updateGestureHandlingMode();
}
- public static void dismissAllKeyPreviews() {
+ public static void setReleasedKeyGraphicsToAllKeys() {
final int trackersSize = sTrackers.size();
for (int i = 0; i < trackersSize; ++i) {
final PointerTracker tracker = sTrackers.get(i);
- tracker.getKeyPreviewText().setVisibility(View.INVISIBLE);
tracker.setReleasedKeyGraphics(tracker.mCurrentKey);
}
}
- // TODO: To handle multi-touch gestures we may want to move this method to
- // {@link PointerTrackerQueue}.
- private static InputPointers getIncrementalBatchPoints() {
- final int trackersSize = sTrackers.size();
- for (int i = 0; i < trackersSize; ++i) {
- final PointerTracker tracker = sTrackers.get(i);
- tracker.mGestureStroke.appendIncrementalBatchPoints(sAggregratedPointers);
- }
- return sAggregratedPointers;
- }
-
- // TODO: To handle multi-touch gestures we may want to move this method to
- // {@link PointerTrackerQueue}.
- private static InputPointers getAllBatchPoints() {
- final int trackersSize = sTrackers.size();
- for (int i = 0; i < trackersSize; ++i) {
- final PointerTracker tracker = sTrackers.get(i);
- tracker.mGestureStroke.appendAllBatchPoints(sAggregratedPointers);
- }
- return sAggregratedPointers;
- }
-
- // TODO: To handle multi-touch gestures we may want to move this method to
- // {@link PointerTrackerQueue}.
- public static void clearBatchInputPointsOfAllPointerTrackers() {
- final int trackersSize = sTrackers.size();
- for (int i = 0; i < trackersSize; ++i) {
- final PointerTracker tracker = sTrackers.get(i);
- tracker.mGestureStroke.reset();
- }
- sAggregratedPointers.reset();
- }
-
- private PointerTracker(int id, KeyEventHandler handler) {
- if (handler == null)
+ private PointerTracker(final int id, final KeyEventHandler handler) {
+ if (handler == null) {
throw new NullPointerException();
+ }
mPointerId = id;
- mGestureStroke = new GestureStroke(id);
+ mGestureStrokeWithPreviewTrail = new GestureStrokeWithPreviewTrail(id);
setKeyDetectorInner(handler.getKeyDetector());
mListener = handler.getKeyboardActionListener();
mDrawingProxy = handler.getDrawingProxy();
mTimerProxy = handler.getTimerProxy();
- mKeyPreviewText = mDrawingProxy.inflateKeyPreviewText();
- }
-
- public TextView getKeyPreviewText() {
- return mKeyPreviewText;
}
// Returns true if keyboard has been changed by this callback.
- private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key) {
- if (mInGesture) {
+ private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) {
+ if (sInGesture) {
return false;
}
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
@@ -337,7 +326,8 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
// Note that we need primaryCode argument because the keyboard may in shifted state and the
// primaryCode is different from {@link Key#mCode}.
- private void callListenerOnCodeInput(Key key, int primaryCode, int x, int y) {
+ private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x,
+ final int y) {
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
final int code = altersCode ? key.mAltCode : primaryCode;
@@ -366,8 +356,9 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
// Note that we need primaryCode argument because the keyboard may in shifted state and the
// primaryCode is different from {@link Key#mCode}.
- private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) {
- if (mInGesture) {
+ private void callListenerOnRelease(final Key key, final int primaryCode,
+ final boolean withSliding) {
+ if (sInGesture) {
return;
}
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
@@ -389,20 +380,19 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
private void callListenerOnCancelInput() {
- if (DEBUG_LISTENER)
+ if (DEBUG_LISTENER) {
Log.d(TAG, "onCancelInput");
+ }
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.pointerTracker_callListenerOnCancelInput();
}
mListener.onCancelInput();
}
- private void setKeyDetectorInner(KeyDetector keyDetector) {
+ private void setKeyDetectorInner(final KeyDetector keyDetector) {
mKeyDetector = keyDetector;
mKeyboard = keyDetector.getKeyboard();
- mIsAlphabetKeyboard = mKeyboard.mId.isAlphabetKeyboard();
- mGestureStroke.setGestureSampleLength(
- mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
+ mGestureStrokeWithPreviewTrail.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth);
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
if (newKey != mCurrentKey) {
if (mDrawingProxy != null) {
@@ -428,11 +418,11 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
return mCurrentKey != null && mCurrentKey.isModifier();
}
- public Key getKeyOn(int x, int y) {
+ public Key getKeyOn(final int x, final int y) {
return mKeyDetector.detectHitKey(x, y);
}
- private void setReleasedKeyGraphics(Key key) {
+ private void setReleasedKeyGraphics(final Key key) {
mDrawingProxy.dismissKeyPreview(this);
if (key == null) {
return;
@@ -463,7 +453,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- private void setPressedKeyGraphics(Key key) {
+ private void setPressedKeyGraphics(final Key key) {
if (key == null) {
return;
}
@@ -475,7 +465,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
return;
}
- if (!key.noKeyPreview() && !mInGesture) {
+ if (!key.noKeyPreview() && !sInGesture) {
mDrawingProxy.showKeyPreview(this);
}
updatePressKeyGraphics(key);
@@ -502,20 +492,18 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- private void updateReleaseKeyGraphics(Key key) {
+ private void updateReleaseKeyGraphics(final Key key) {
key.onReleased();
mDrawingProxy.invalidateKey(key);
}
- private void updatePressKeyGraphics(Key key) {
+ private void updatePressKeyGraphics(final Key key) {
key.onPressed();
mDrawingProxy.invalidateKey(key);
}
- public void drawGestureTrail(Canvas canvas, Paint paint) {
- if (mInGesture) {
- mGestureStroke.drawGestureTrail(canvas, paint, mLastX, mLastY);
- }
+ public GestureStrokeWithPreviewTrail getGestureStrokeWithPreviewTrail() {
+ return mGestureStrokeWithPreviewTrail;
}
public int getLastX() {
@@ -530,77 +518,91 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
return mDownTime;
}
- private Key onDownKey(int x, int y, long eventTime) {
+ private Key onDownKey(final int x, final int y, final long eventTime) {
mDownTime = eventTime;
return onMoveToNewKey(onMoveKeyInternal(x, y), x, y);
}
- private Key onMoveKeyInternal(int x, int y) {
+ private Key onMoveKeyInternal(final int x, final int y) {
mLastX = x;
mLastY = y;
return mKeyDetector.detectHitKey(x, y);
}
- private Key onMoveKey(int x, int y) {
+ private Key onMoveKey(final int x, final int y) {
return onMoveKeyInternal(x, y);
}
- private Key onMoveToNewKey(Key newKey, int x, int y) {
+ private Key onMoveToNewKey(final Key newKey, final int x, final int y) {
mCurrentKey = newKey;
mKeyX = x;
mKeyY = y;
return newKey;
}
+ private static int getActivePointerTrackerCount() {
+ return (sPointerTrackerQueue == null) ? 1 : sPointerTrackerQueue.size();
+ }
+
private void startBatchInput() {
if (DEBUG_LISTENER) {
Log.d(TAG, "onStartBatchInput");
}
- mInGesture = true;
+ sInGesture = true;
mListener.onStartBatchInput();
+ mDrawingProxy.showGesturePreviewTrail(this);
}
- private void updateBatchInput(InputPointers batchPoints) {
- if (DEBUG_LISTENER) {
- Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize());
+ private void updateBatchInput(final long eventTime) {
+ synchronized (sAggregratedPointers) {
+ mGestureStrokeWithPreviewTrail.appendIncrementalBatchPoints(sAggregratedPointers);
+ final int size = sAggregratedPointers.getPointerSize();
+ if (size > sLastRecognitionPointSize
+ && eventTime > sLastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME) {
+ sLastRecognitionPointSize = size;
+ sLastRecognitionTime = eventTime;
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size);
+ }
+ mListener.onUpdateBatchInput(sAggregratedPointers);
+ }
}
- mListener.onUpdateBatchInput(batchPoints);
+ mDrawingProxy.showGesturePreviewTrail(this);
}
- private void endBatchInput(InputPointers batchPoints) {
- if (DEBUG_LISTENER) {
- Log.d(TAG, "onEndBatchInput: batchPoints=" + batchPoints.getPointerSize());
+ private void endBatchInput() {
+ synchronized (sAggregratedPointers) {
+ mGestureStrokeWithPreviewTrail.appendAllBatchPoints(sAggregratedPointers);
+ if (getActivePointerTrackerCount() == 1) {
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, "onEndBatchInput: batchPoints="
+ + sAggregratedPointers.getPointerSize());
+ }
+ sInGesture = false;
+ mListener.onEndBatchInput(sAggregratedPointers);
+ clearBatchInputPointsOfAllPointerTrackers();
+ }
}
- mListener.onEndBatchInput(batchPoints);
- clearBatchInputRecognitionStateOfThisPointerTracker();
- clearBatchInputPointsOfAllPointerTrackers();
- sWasInGesture = true;
+ mDrawingProxy.showGesturePreviewTrail(this);
}
- private void abortBatchInput() {
- clearBatchInputRecognitionStateOfThisPointerTracker();
+ private static void abortBatchInput() {
clearBatchInputPointsOfAllPointerTrackers();
}
- private void clearBatchInputRecognitionStateOfThisPointerTracker() {
- mIsPossibleGesture = false;
- mInGesture = false;
- mLastRecognitionPointSize = 0;
- mLastRecognitionTime = 0;
- }
-
- private boolean updateBatchInputRecognitionState(long eventTime, int size) {
- if (size > mLastRecognitionPointSize
- && eventTime > mLastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME) {
- mLastRecognitionPointSize = size;
- mLastRecognitionTime = eventTime;
- return true;
+ private static void clearBatchInputPointsOfAllPointerTrackers() {
+ final int trackersSize = sTrackers.size();
+ for (int i = 0; i < trackersSize; ++i) {
+ final PointerTracker tracker = sTrackers.get(i);
+ tracker.mGestureStrokeWithPreviewTrail.reset();
}
- return false;
+ sAggregratedPointers.reset();
+ sLastRecognitionPointSize = 0;
+ sLastRecognitionTime = 0;
}
- public void processMotionEvent(int action, int x, int y, long eventTime,
- KeyEventHandler handler) {
+ public void processMotionEvent(final int action, final int x, final int y, final long eventTime,
+ final KeyEventHandler handler) {
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
@@ -619,9 +621,11 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- public void onDownEvent(int x, int y, long eventTime, KeyEventHandler handler) {
- if (DEBUG_EVENT)
+ public void onDownEvent(final int x, final int y, final long eventTime,
+ final KeyEventHandler handler) {
+ if (DEBUG_EVENT) {
printTouchEvent("onDownEvent:", x, y, eventTime);
+ }
mDrawingProxy = handler.getDrawingProxy();
mTimerProxy = handler.getTimerProxy();
@@ -633,7 +637,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
final int dx = x - mLastX;
final int dy = y - mLastY;
final int distanceSquared = (dx * dx + dy * dy);
- if (distanceSquared < sTouchNoiseThresholdDistanceSquared) {
+ if (distanceSquared < sParams.mTouchNoiseThresholdDistanceSquared) {
if (DEBUG_MODE)
Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT
+ " distance=" + distanceSquared);
@@ -645,8 +649,8 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- final PointerTrackerQueue queue = sPointerTrackerQueue;
final Key key = getKeyOn(x, y);
+ final PointerTrackerQueue queue = sPointerTrackerQueue;
if (queue != null) {
if (key != null && key.isModifier()) {
// Before processing a down event of modifier key, all pointers already being
@@ -656,20 +660,30 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
queue.add(this);
}
onDownEventInternal(x, y, eventTime);
- if (queue != null && queue.size() == 1) {
- mIsPossibleGesture = false;
+ if (!sShouldHandleGesture) {
+ return;
+ }
+ final int activePointerTrackerCount = getActivePointerTrackerCount();
+ if (activePointerTrackerCount == 1) {
+ mIsDetectingGesture = false;
// A gesture should start only from the letter key.
- if (sShouldHandleGesture && mIsAlphabetKeyboard && !mIsShowingMoreKeysPanel
- && key != null && Keyboard.isLetterCode(key.mCode)) {
- mIsPossibleGesture = true;
- // TODO: pointer times should be relative to first down even in entire batch input
- // instead of resetting to 0 for each new down event.
- mGestureStroke.addPoint(x, y, 0, false);
+ final boolean isAlphabetKeyboard = (mKeyboard != null)
+ && mKeyboard.mId.isAlphabetKeyboard();
+ if (isAlphabetKeyboard && !mIsShowingMoreKeysPanel && key != null
+ && Keyboard.isLetterCode(key.mCode)) {
+ mIsDetectingGesture = true;
+ sGestureFirstDownTime = eventTime;
+ mGestureStrokeWithPreviewTrail.addPoint(x, y, 0, false /* isHistorical */);
}
+ } else if (sInGesture && activePointerTrackerCount > 1) {
+ mIsDetectingGesture = true;
+ final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime);
+ mGestureStrokeWithPreviewTrail.addPoint(x, y, elapsedTimeFromFirstDown,
+ false /* isHistorical */);
}
}
- private void onDownEventInternal(int x, int y, long eventTime) {
+ private void onDownEventInternal(final int x, final int y, final long eventTime) {
Key key = onDownKey(x, y, eventTime);
// Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding
// from modifier key, or 3) this pointer's KeyDetector always allows sliding input.
@@ -694,40 +708,38 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- private void startSlidingKeyInput(Key key) {
+ private void startSlidingKeyInput(final Key key) {
if (!mIsInSlidingKeyInput) {
mIgnoreModifierKey = key.isModifier();
}
mIsInSlidingKeyInput = true;
}
- private void onGestureMoveEvent(PointerTracker tracker, int x, int y, long eventTime,
- boolean isHistorical, Key key) {
- final int gestureTime = (int)(eventTime - tracker.getDownTime());
- if (sShouldHandleGesture && mIsPossibleGesture) {
- final GestureStroke stroke = mGestureStroke;
+ private void onGestureMoveEvent(final int x, final int y, final long eventTime,
+ final boolean isHistorical, final Key key) {
+ final int gestureTime = (int)(eventTime - sGestureFirstDownTime);
+ if (mIsDetectingGesture) {
+ final GestureStroke stroke = mGestureStrokeWithPreviewTrail;
stroke.addPoint(x, y, gestureTime, isHistorical);
- if (!mInGesture && stroke.isStartOfAGesture(gestureTime, sWasInGesture)) {
+ if (!sInGesture && stroke.isStartOfAGesture()) {
startBatchInput();
}
- }
- if (key != null && mInGesture) {
- final InputPointers batchPoints = getIncrementalBatchPoints();
- mDrawingProxy.showGestureTrail(this);
- if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) {
- updateBatchInput(batchPoints);
+ if (sInGesture && key != null) {
+ updateBatchInput(eventTime);
}
}
}
- public void onMoveEvent(int x, int y, long eventTime, MotionEvent me) {
- if (DEBUG_MOVE_EVENT)
+ public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) {
+ if (DEBUG_MOVE_EVENT) {
printTouchEvent("onMoveEvent:", x, y, eventTime);
- if (mKeyAlreadyProcessed)
+ }
+ if (mKeyAlreadyProcessed) {
return;
+ }
- if (me != null) {
+ if (sShouldHandleGesture && me != null) {
// Add historical points to gesture path.
final int pointerIndex = me.findPointerIndex(mPointerId);
final int historicalSize = me.getHistorySize();
@@ -735,24 +747,31 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
final int historicalX = (int)me.getHistoricalX(pointerIndex, h);
final int historicalY = (int)me.getHistoricalY(pointerIndex, h);
final long historicalTime = me.getHistoricalEventTime(h);
- onGestureMoveEvent(this, historicalX, historicalY, historicalTime,
+ onGestureMoveEvent(historicalX, historicalY, historicalTime,
true /* isHistorical */, null);
}
}
+ onMoveEventInternal(x, y, eventTime);
+ }
+
+ private void onMoveEventInternal(final int x, final int y, final long eventTime) {
final int lastX = mLastX;
final int lastY = mLastY;
final Key oldKey = mCurrentKey;
Key key = onMoveKey(x, y);
- // Register move event on gesture tracker.
- onGestureMoveEvent(this, x, y, eventTime, false /* isHistorical */, key);
- if (mInGesture) {
- mIgnoreModifierKey = true;
- mTimerProxy.cancelLongPressTimer();
- mIsInSlidingKeyInput = true;
- mCurrentKey = null;
- setReleasedKeyGraphics(oldKey);
+ if (sShouldHandleGesture) {
+ // Register move event on gesture tracker.
+ onGestureMoveEvent(x, y, eventTime, false /* isHistorical */, key);
+ if (sInGesture) {
+ mIgnoreModifierKey = true;
+ mTimerProxy.cancelLongPressTimer();
+ mIsInSlidingKeyInput = true;
+ mCurrentKey = null;
+ setReleasedKeyGraphics(oldKey);
+ return;
+ }
}
if (key != null) {
@@ -797,7 +816,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
// TODO: Should find a way to balance gesture detection and this hack.
if (sNeedsPhantomSuddenMoveEventHack
&& lastMoveSquared >= mKeyQuarterWidthSquared
- && !mIsPossibleGesture) {
+ && !mIsDetectingGesture) {
if (DEBUG_MODE) {
Log.w(TAG, String.format("onMoveEvent:"
+ " phantom sudden move event is translated to "
@@ -815,11 +834,11 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
// touch panels when there are close multiple touches.
// Caveat: When in chording input mode with a modifier key, we don't use
// this hack.
- if (me != null && me.getPointerCount() > 1
+ if (getActivePointerTrackerCount() > 1 && sPointerTrackerQueue != null
&& !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) {
onUpEventInternal();
}
- if (!mIsPossibleGesture) {
+ if (!mIsDetectingGesture) {
mKeyAlreadyProcessed = true;
}
setReleasedKeyGraphics(oldKey);
@@ -837,7 +856,7 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
if (mIsAllowedSlidingKeyInput) {
onMoveToNewKey(key, x, y);
} else {
- if (!mIsPossibleGesture) {
+ if (!mIsDetectingGesture) {
mKeyAlreadyProcessed = true;
}
}
@@ -845,13 +864,14 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- public void onUpEvent(int x, int y, long eventTime) {
- if (DEBUG_EVENT)
+ public void onUpEvent(final int x, final int y, final long eventTime) {
+ if (DEBUG_EVENT) {
printTouchEvent("onUpEvent :", x, y, eventTime);
+ }
final PointerTrackerQueue queue = sPointerTrackerQueue;
if (queue != null) {
- if (!mInGesture) {
+ if (!sInGesture) {
if (mCurrentKey != null && mCurrentKey.isModifier()) {
// Before processing an up event of modifier key, all pointers already being
// tracked should be released.
@@ -860,18 +880,21 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
queue.releaseAllPointersOlderThan(this, eventTime);
}
}
- queue.remove(this);
}
onUpEventInternal();
+ if (queue != null) {
+ queue.remove(this);
+ }
}
// Let this pointer tracker know that one of newer-than-this pointer trackers got an up event.
// This pointer tracker needs to keep the key top graphics "pressed", but needs to get a
// "virtual" up event.
@Override
- public void onPhantomUpEvent(long eventTime) {
- if (DEBUG_EVENT)
+ public void onPhantomUpEvent(final long eventTime) {
+ if (DEBUG_EVENT) {
printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime);
+ }
onUpEventInternal();
mKeyAlreadyProcessed = true;
}
@@ -879,37 +902,35 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
private void onUpEventInternal() {
mTimerProxy.cancelKeyTimers();
mIsInSlidingKeyInput = false;
- mIsPossibleGesture = false;
+ mIsDetectingGesture = false;
+ final Key currentKey = mCurrentKey;
+ mCurrentKey = null;
// Release the last pressed key.
- setReleasedKeyGraphics(mCurrentKey);
+ setReleasedKeyGraphics(currentKey);
if (mIsShowingMoreKeysPanel) {
mDrawingProxy.dismissMoreKeysPanel();
mIsShowingMoreKeysPanel = false;
}
- if (mInGesture) {
- // Register up event on gesture tracker.
- // TODO: Figure out how to deal with multiple fingers that are in gesture, sliding,
- // and/or tapping mode?
- endBatchInput(getAllBatchPoints());
- if (mCurrentKey != null) {
- callListenerOnRelease(mCurrentKey, mCurrentKey.mCode, true);
- mCurrentKey = null;
+ if (sInGesture) {
+ if (currentKey != null) {
+ callListenerOnRelease(currentKey, currentKey.mCode, true);
}
- mDrawingProxy.showGestureTrail(this);
+ endBatchInput();
return;
}
- // This event will be recognized as a regular code input. Clear unused batch points so they
- // are not mistakenly included in the next batch event.
+ // This event will be recognized as a regular code input. Clear unused possible batch points
+ // so they are not mistakenly displayed as preview.
clearBatchInputPointsOfAllPointerTrackers();
- if (mKeyAlreadyProcessed)
+ if (mKeyAlreadyProcessed) {
return;
- if (mCurrentKey != null && !mCurrentKey.isRepeatable()) {
- detectAndSendKey(mCurrentKey, mKeyX, mKeyY);
+ }
+ if (currentKey != null && !currentKey.isRepeatable()) {
+ detectAndSendKey(currentKey, mKeyX, mKeyY);
}
}
- public void onShowMoreKeysPanel(int x, int y, KeyEventHandler handler) {
+ public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) {
abortBatchInput();
onLongPressed();
mIsShowingMoreKeysPanel = true;
@@ -925,9 +946,10 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- public void onCancelEvent(int x, int y, long eventTime) {
- if (DEBUG_EVENT)
+ public void onCancelEvent(final int x, final int y, final long eventTime) {
+ if (DEBUG_EVENT) {
printTouchEvent("onCancelEvt:", x, y, eventTime);
+ }
final PointerTrackerQueue queue = sPointerTrackerQueue;
if (queue != null) {
@@ -947,24 +969,25 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- private void startRepeatKey(Key key) {
- if (key != null && key.isRepeatable() && !mInGesture) {
+ private void startRepeatKey(final Key key) {
+ if (key != null && key.isRepeatable() && !sInGesture) {
onRegisterKey(key);
mTimerProxy.startKeyRepeatTimer(this);
}
}
- public void onRegisterKey(Key key) {
+ public void onRegisterKey(final Key key) {
if (key != null) {
detectAndSendKey(key, key.mX, key.mY);
mTimerProxy.startTypingStateTimer(key);
}
}
- private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, Key newKey) {
- if (mKeyDetector == null)
+ private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final Key newKey) {
+ if (mKeyDetector == null) {
throw new NullPointerException("keyboard and/or key detector not set");
- Key curKey = mCurrentKey;
+ }
+ final Key curKey = mCurrentKey;
if (newKey == curKey) {
return false;
} else if (curKey != null) {
@@ -975,25 +998,25 @@ public class PointerTracker implements PointerTrackerQueue.ElementActions {
}
}
- private void startLongPressTimer(Key key) {
- if (key != null && key.isLongPressEnabled() && !mInGesture) {
+ private void startLongPressTimer(final Key key) {
+ if (key != null && key.isLongPressEnabled() && !sInGesture) {
mTimerProxy.startLongPressTimer(this);
}
}
- private void detectAndSendKey(Key key, int x, int y) {
+ private void detectAndSendKey(final Key key, final int x, final int y) {
if (key == null) {
callListenerOnCancelInput();
return;
}
- int code = key.mCode;
+ final int code = key.mCode;
callListenerOnCodeInput(key, code, x, y);
callListenerOnRelease(key, code, false);
- sWasInGesture = false;
}
- private void printTouchEvent(String title, int x, int y, long eventTime) {
+ private void printTouchEvent(final String title, final int x, final int y,
+ final long eventTime) {
final Key key = mKeyDetector.detectHitKey(x, y);
final String code = KeyDetector.printableCode(key);
Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title,
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index ae123e29a..71bf31faa 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -18,9 +18,9 @@ package com.android.inputmethod.keyboard;
import android.graphics.Rect;
import android.text.TextUtils;
-import android.util.FloatMath;
import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.JniUtils;
import java.util.Arrays;
@@ -112,7 +112,7 @@ public class ProximityInfo {
final Key[] keys = mKeys;
final TouchPositionCorrection touchPositionCorrection = mTouchPositionCorrection;
final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
- Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE);
+ Arrays.fill(proximityCharsArray, Constants.NOT_A_CODE);
for (int i = 0; i < mGridSize; ++i) {
final int proximityCharsLength = gridNeighborKeys[i].length;
for (int j = 0; j < proximityCharsLength; ++j) {
@@ -155,7 +155,9 @@ public class ProximityInfo {
final float radius = touchPositionCorrection.mRadii[row];
sweetSpotCenterXs[i] = hitBox.exactCenterX() + x * hitBoxWidth;
sweetSpotCenterYs[i] = hitBox.exactCenterY() + y * hitBoxHeight;
- sweetSpotRadii[i] = radius * FloatMath.sqrt(
+ // Note that, in recent versions of Android, FloatMath is actually slower than
+ // java.lang.Math due to the way the JIT optimizes java.lang.Math.
+ sweetSpotRadii[i] = radius * (float)Math.sqrt(
hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
}
}
@@ -233,7 +235,7 @@ public class ProximityInfo {
dest[index++] = code;
}
if (index < destLength) {
- dest[index] = KeyDetector.NOT_A_CODE;
+ dest[index] = Constants.NOT_A_CODE;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
new file mode 100644
index 000000000..e814d8009
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.SystemClock;
+
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResizableIntArray;
+
+class GesturePreviewTrail {
+ private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewTrail.PREVIEW_CAPACITY;
+
+ private final GesturePreviewTrailParams mPreviewParams;
+ private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
+ private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
+ private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY);
+ private int mCurrentStrokeId = -1;
+ private long mCurrentDownTime;
+ private int mTrailStartIndex;
+
+ // Use this value as imaginary zero because x-coordinates may be zero.
+ private static final int DOWN_EVENT_MARKER = -128;
+
+ static class GesturePreviewTrailParams {
+ public final int mFadeoutStartDelay;
+ public final int mFadeoutDuration;
+ public final int mUpdateInterval;
+
+ public GesturePreviewTrailParams(final TypedArray keyboardViewAttr) {
+ mFadeoutStartDelay = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_gesturePreviewTrailFadeoutStartDelay, 0);
+ mFadeoutDuration = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_gesturePreviewTrailFadeoutDuration, 0);
+ mUpdateInterval = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_gesturePreviewTrailUpdateInterval, 0);
+ }
+ }
+
+ public GesturePreviewTrail(final GesturePreviewTrailParams params) {
+ mPreviewParams = params;
+ }
+
+ private static int markAsDownEvent(final int xCoord) {
+ return DOWN_EVENT_MARKER - xCoord;
+ }
+
+ private static boolean isDownEventXCoord(final int xCoordOrMark) {
+ return xCoordOrMark <= DOWN_EVENT_MARKER;
+ }
+
+ private static int getXCoordValue(final int xCoordOrMark) {
+ return isDownEventXCoord(xCoordOrMark)
+ ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark;
+ }
+
+ public void addStroke(final GestureStrokeWithPreviewTrail stroke, final long downTime) {
+ final int strokeId = stroke.getGestureStrokeId();
+ final boolean isNewStroke = strokeId != mCurrentStrokeId;
+ final int trailSize = mEventTimes.getLength();
+ stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates);
+ final int newTrailSize = mEventTimes.getLength();
+ if (stroke.getGestureStrokePreviewSize() == 0) {
+ return;
+ }
+ if (isNewStroke) {
+ final int elapsedTime = (int)(downTime - mCurrentDownTime);
+ final int[] eventTimes = mEventTimes.getPrimitiveArray();
+ for (int i = mTrailStartIndex; i < trailSize; i++) {
+ eventTimes[i] -= elapsedTime;
+ }
+
+ if (newTrailSize > trailSize) {
+ final int[] xCoords = mXCoordinates.getPrimitiveArray();
+ xCoords[trailSize] = markAsDownEvent(xCoords[trailSize]);
+ }
+ mCurrentDownTime = downTime;
+ mCurrentStrokeId = strokeId;
+ }
+ }
+
+ private int getAlpha(final int elapsedTime) {
+ if (elapsedTime < mPreviewParams.mFadeoutStartDelay) {
+ return Constants.Color.ALPHA_OPAQUE;
+ }
+ final int decreasingAlpha = Constants.Color.ALPHA_OPAQUE
+ * (elapsedTime - mPreviewParams.mFadeoutStartDelay)
+ / mPreviewParams.mFadeoutDuration;
+ return Constants.Color.ALPHA_OPAQUE - decreasingAlpha;
+ }
+
+ /**
+ * Draw gesture preview trail
+ * @param canvas The canvas to draw the gesture preview trail
+ * @param paint The paint object to be used to draw the gesture preview trail
+ * @return true if some gesture preview trails remain to be drawn
+ */
+ public boolean drawGestureTrail(final Canvas canvas, final Paint paint) {
+ final int trailSize = mEventTimes.getLength();
+ if (trailSize == 0) {
+ return false;
+ }
+
+ final int[] eventTimes = mEventTimes.getPrimitiveArray();
+ final int[] xCoords = mXCoordinates.getPrimitiveArray();
+ final int[] yCoords = mYCoordinates.getPrimitiveArray();
+ final int sinceDown = (int)(SystemClock.uptimeMillis() - mCurrentDownTime);
+ final int lingeringDuration = mPreviewParams.mFadeoutStartDelay
+ + mPreviewParams.mFadeoutDuration;
+ int startIndex;
+ for (startIndex = mTrailStartIndex; startIndex < trailSize; startIndex++) {
+ final int elapsedTime = sinceDown - eventTimes[startIndex];
+ // Skip too old trail points.
+ if (elapsedTime < lingeringDuration) {
+ break;
+ }
+ }
+ mTrailStartIndex = startIndex;
+
+ if (startIndex < trailSize) {
+ int lastX = getXCoordValue(xCoords[startIndex]);
+ int lastY = yCoords[startIndex];
+ for (int i = startIndex + 1; i < trailSize - 1; i++) {
+ final int x = xCoords[i];
+ final int y = yCoords[i];
+ final int elapsedTime = sinceDown - eventTimes[i];
+ // Draw trail line only when the current point isn't a down point.
+ if (!isDownEventXCoord(x)) {
+ paint.setAlpha(getAlpha(elapsedTime));
+ canvas.drawLine(lastX, lastY, x, y, paint);
+ }
+ lastX = getXCoordValue(x);
+ lastY = y;
+ }
+ }
+
+ final int newSize = trailSize - startIndex;
+ if (newSize < startIndex) {
+ mTrailStartIndex = 0;
+ if (newSize > 0) {
+ System.arraycopy(eventTimes, startIndex, eventTimes, 0, newSize);
+ System.arraycopy(xCoords, startIndex, xCoords, 0, newSize);
+ System.arraycopy(yCoords, startIndex, yCoords, 0, newSize);
+ }
+ mEventTimes.setLength(newSize);
+ mXCoordinates.setLength(newSize);
+ mYCoordinates.setLength(newSize);
+ }
+ return newSize > 0;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index 28d6c1d07..825134468 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -14,11 +14,6 @@
package com.android.inputmethod.keyboard.internal;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.util.FloatMath;
-
-import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.ResizableIntArray;
@@ -38,44 +33,30 @@ public class GestureStroke {
private int mLastPointY;
private int mMinGestureLength;
- private int mMinGestureLengthWhileInGesture;
private int mMinGestureSampleLength;
// TODO: Move some of these to resource.
- private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 1.0f;
- private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH_WHILE_IN_GESTURE = 0.5f;
- private static final int MIN_GESTURE_DURATION = 150; // msec
- private static final int MIN_GESTURE_DURATION_WHILE_IN_GESTURE = 75; // msec
- private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT = 1.0f / 6.0f;
+ private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 0.75f;
+ private static final int MIN_GESTURE_DURATION = 100; // msec
+ private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f;
private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; // dip/msec
private static final float GESTURE_RECOG_CURVATURE_THRESHOLD = (float)(Math.PI / 4.0f);
- private static final float DOUBLE_PI = (float)(2 * Math.PI);
+ private static final float DOUBLE_PI = (float)(2.0f * Math.PI);
- // Fade based on number of gesture samples, see MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT
- private static final int DRAWING_GESTURE_FADE_START = 10;
- private static final int DRAWING_GESTURE_FADE_RATE = 6;
-
- public GestureStroke(int pointerId) {
+ public GestureStroke(final int pointerId) {
mPointerId = pointerId;
- reset();
}
- public void setGestureSampleLength(final int keyWidth, final int keyHeight) {
+ public void setGestureSampleLength(final int keyWidth) {
// TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key?
mMinGestureLength = (int)(keyWidth * MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH);
- mMinGestureLengthWhileInGesture = (int)(
- keyWidth * MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH_WHILE_IN_GESTURE);
- mMinGestureSampleLength = (int)(keyHeight * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT);
+ mMinGestureSampleLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH);
}
- public boolean isStartOfAGesture(final int downDuration, final boolean wasInGesture) {
- // The tolerance of the time duration and the stroke length to detect the start of a
- // gesture stroke should be eased when the previous input was a gesture input.
- if (wasInGesture) {
- return downDuration > MIN_GESTURE_DURATION_WHILE_IN_GESTURE
- && mLength > mMinGestureLengthWhileInGesture;
- }
+ public boolean isStartOfAGesture() {
+ final int size = mEventTimes.getLength();
+ final int downDuration = (size > 0) ? mEventTimes.get(size - 1) : 0;
return downDuration > MIN_GESTURE_DURATION && mLength > mMinGestureLength;
}
@@ -149,23 +130,29 @@ public class GestureStroke {
}
private void appendBatchPoints(final InputPointers out, final int size) {
+ final int length = size - mLastIncrementalBatchSize;
+ if (length <= 0) {
+ return;
+ }
out.append(mPointerId, mEventTimes, mXCoordinates, mYCoordinates,
- mLastIncrementalBatchSize, size - mLastIncrementalBatchSize);
+ mLastIncrementalBatchSize, length);
mLastIncrementalBatchSize = size;
}
- private static float getDistance(final int p1x, final int p1y,
- final int p2x, final int p2y) {
- final float dx = p1x - p2x;
- final float dy = p1y - p2y;
- // TODO: Optimize out this {@link FloatMath#sqrt(float)} call.
- return FloatMath.sqrt(dx * dx + dy * dy);
+ private static float getDistance(final int x1, final int y1, final int x2, final int y2) {
+ final float dx = x1 - x2;
+ final float dy = y1 - y2;
+ // Note that, in recent versions of Android, FloatMath is actually slower than
+ // java.lang.Math due to the way the JIT optimizes java.lang.Math.
+ return (float)Math.sqrt(dx * dx + dy * dy);
}
- private static float getAngle(final int p1x, final int p1y, final int p2x, final int p2y) {
- final int dx = p1x - p2x;
- final int dy = p1y - p2y;
+ private static float getAngle(final int x1, final int y1, final int x2, final int y2) {
+ final int dx = x1 - x2;
+ final int dy = y1 - y2;
if (dx == 0 && dy == 0) return 0;
+ // Would it be faster to call atan2f() directly via JNI? Not sure about what the JIT
+ // does with Math.atan2().
return (float)Math.atan2(dy, dx);
}
@@ -176,23 +163,4 @@ public class GestureStroke {
}
return diff;
}
-
- public void drawGestureTrail(Canvas canvas, Paint paint, int lastX, int lastY) {
- // TODO: These paint parameter interpolation should be tunable, possibly introduce an object
- // that implements an interface such as Paint getPaint(int step, int strokePoints)
- final int size = mXCoordinates.getLength();
- int[] xCoords = mXCoordinates.getPrimitiveArray();
- int[] yCoords = mYCoordinates.getPrimitiveArray();
- int alpha = Constants.Color.ALPHA_OPAQUE;
- for (int i = size - 1; i > 0 && alpha > 0; i--) {
- paint.setAlpha(alpha);
- if (size - i > DRAWING_GESTURE_FADE_START) {
- alpha -= DRAWING_GESTURE_FADE_RATE;
- }
- canvas.drawLine(xCoords[i - 1], yCoords[i - 1], xCoords[i], yCoords[i], paint);
- if (i == size - 1) {
- canvas.drawLine(lastX, lastY, xCoords[i], yCoords[i], paint);
- }
- }
- }
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java
new file mode 100644
index 000000000..6c1a9bc01
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import com.android.inputmethod.latin.ResizableIntArray;
+
+public class GestureStrokeWithPreviewTrail extends GestureStroke {
+ public static final int PREVIEW_CAPACITY = 256;
+
+ private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY);
+ private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
+ private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
+
+ private int mStrokeId;
+ private int mLastPreviewSize;
+
+ public GestureStrokeWithPreviewTrail(final int pointerId) {
+ super(pointerId);
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ mStrokeId++;
+ mLastPreviewSize = 0;
+ mPreviewEventTimes.setLength(0);
+ mPreviewXCoordinates.setLength(0);
+ mPreviewYCoordinates.setLength(0);
+ }
+
+ public int getGestureStrokeId() {
+ return mStrokeId;
+ }
+
+ public int getGestureStrokePreviewSize() {
+ return mPreviewEventTimes.getLength();
+ }
+
+ @Override
+ public void addPoint(final int x, final int y, final int time, final boolean isHistorical) {
+ super.addPoint(x, y, time, isHistorical);
+ mPreviewEventTimes.add(time);
+ mPreviewXCoordinates.add(x);
+ mPreviewYCoordinates.add(y);
+ }
+
+ public void appendPreviewStroke(final ResizableIntArray eventTimes,
+ final ResizableIntArray xCoords, final ResizableIntArray yCoords) {
+ final int length = mPreviewEventTimes.getLength() - mLastPreviewSize;
+ if (length <= 0) {
+ return;
+ }
+ eventTimes.append(mPreviewEventTimes, mLastPreviewSize, length);
+ xCoords.append(mPreviewXCoordinates, mLastPreviewSize, length);
+ yCoords.append(mPreviewYCoordinates, mLastPreviewSize, length);
+ mLastPreviewSize = mPreviewEventTimes.getLength();
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index 94a7b826f..13214bb9f 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -21,6 +21,7 @@ import static com.android.inputmethod.keyboard.Keyboard.CODE_UNSPECIFIED;
import android.text.TextUtils;
import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.StringUtils;
@@ -258,7 +259,7 @@ public class KeySpecParser {
throw new IllegalArgumentException();
}
- final ArrayList list = new ArrayList(end - start);
+ final ArrayList list = CollectionUtils.newArrayList(end - start);
for (int i = start; i < end; i++) {
list.add(array[i]);
}
@@ -438,7 +439,7 @@ public class KeySpecParser {
// Skip empty entry.
if (pos - start > 0) {
if (list == null) {
- list = new ArrayList();
+ list = CollectionUtils.newArrayList();
}
list.add(text.substring(start, pos));
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
index 291b3b943..e40cf45cc 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
@@ -21,6 +21,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.XmlParseUtils;
@@ -33,7 +34,7 @@ public class KeyStyles {
private static final String TAG = KeyStyles.class.getSimpleName();
private static final boolean DEBUG = false;
- final HashMap mStyles = new HashMap();
+ final HashMap mStyles = CollectionUtils.newHashMap();
final KeyboardTextsSet mTextsSet;
private final KeyStyle mEmptyKeyStyle;
@@ -90,7 +91,7 @@ public class KeyStyles {
private class DeclaredKeyStyle extends KeyStyle {
private final String mParentStyleName;
- private final SparseArray