aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java38
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java51
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java58
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java31
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java21
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java14
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java15
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java17
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java4
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java4
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java3
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java9
-rw-r--r--java/src/com/android/inputmethod/latin/utils/RunInLocale.java20
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java2
18 files changed, 187 insertions, 112 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index c628c5b09..063f2113d 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -159,8 +159,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
// Add the virtual children of the root View.
final Keyboard keyboard = mKeyboardView.getKeyboard();
- final Key[] keys = keyboard.getKeys();
- for (Key key : keys) {
+ for (final Key key : keyboard.getSortedKeys()) {
final int childVirtualViewId = generateVirtualViewIdForKey(key);
rootInfo.addChild(mKeyboardView, childVirtualViewId);
}
@@ -308,8 +307,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
}
mVirtualViewIdToKey.clear();
- final Key[] keys = keyboard.getKeys();
- for (Key key : keys) {
+ for (final Key key : keyboard.getSortedKeys()) {
final int virtualViewId = generateVirtualViewIdForKey(key);
mVirtualViewIdToKey.put(virtualViewId, key);
}
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index 8822ccec9..d8b5758a6 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -58,9 +58,10 @@ import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.ResourceUtils;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -123,7 +124,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
"places",
"symbols",
"emoticons" };
- private static final int[] sCategoryIcon = new int[] {
+ private static final int[] sCategoryIcon = {
R.drawable.ic_emoji_recent_light,
R.drawable.ic_emoji_people_light,
R.drawable.ic_emoji_objects_light,
@@ -133,6 +134,14 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
0 };
private static final String[] sCategoryLabel =
{ null, null, null, null, null, null, ":-)" };
+ private static final int[] sAccessibilityDescriptionResourceIdsForCategories = {
+ R.string.spoken_descrption_emoji_category_recents,
+ R.string.spoken_descrption_emoji_category_people,
+ R.string.spoken_descrption_emoji_category_objects,
+ R.string.spoken_descrption_emoji_category_nature,
+ R.string.spoken_descrption_emoji_category_places,
+ R.string.spoken_descrption_emoji_category_symbols,
+ R.string.spoken_descrption_emoji_category_emoticons };
private static final int[] sCategoryElementId = {
KeyboardId.ELEMENT_EMOJI_RECENTS,
KeyboardId.ELEMENT_EMOJI_CATEGORY1,
@@ -142,6 +151,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
KeyboardId.ELEMENT_EMOJI_CATEGORY5,
KeyboardId.ELEMENT_EMOJI_CATEGORY6 };
private final SharedPreferences mPrefs;
+ private final Resources mRes;
private final int mMaxPageKeyCount;
private final KeyboardLayoutSet mLayoutSet;
private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
@@ -156,6 +166,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
public EmojiCategory(final SharedPreferences prefs, final Resources res,
final KeyboardLayoutSet layoutSet) {
mPrefs = prefs;
+ mRes = res;
mMaxPageKeyCount = res.getInteger(R.integer.config_emoji_keyboard_max_page_key_count);
mLayoutSet = layoutSet;
for (int i = 0; i < sCategoryName.length; ++i) {
@@ -206,6 +217,10 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
return sCategoryLabel[categoryId];
}
+ public String getAccessibilityDescription(final int categoryId) {
+ return mRes.getString(sAccessibilityDescriptionResourceIdsForCategories[categoryId]);
+ }
+
public ArrayList<CategoryProperties> getShownCategories() {
return mShownCategories;
}
@@ -283,7 +298,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
private int getCategoryPageCount(final int categoryId) {
final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
- return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1;
+ return (keyboard.getSortedKeys().size() - 1) / mMaxPageKeyCount + 1;
}
// Returns a pair of the category id and the category page id from the view pager's page
@@ -332,7 +347,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
}
final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
- final Key[][] sortedKeys = sortKeysIntoPages(keyboard.getKeys(), mMaxPageKeyCount);
+ final Key[][] sortedKeys = sortKeysIntoPages(
+ keyboard.getSortedKeys(), mMaxPageKeyCount);
for (int pageId = 0; pageId < sortedKeys.length; ++pageId) {
final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs,
mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
@@ -380,13 +396,13 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
}
};
- private static Key[][] sortKeysIntoPages(final Key[] inKeys, final int maxPageCount) {
- final Key[] keys = Arrays.copyOf(inKeys, inKeys.length);
- Arrays.sort(keys, 0, keys.length, EMOJI_KEY_COMPARATOR);
- final int pageCount = (keys.length - 1) / maxPageCount + 1;
+ private static Key[][] sortKeysIntoPages(final List<Key> inKeys, final int maxPageCount) {
+ final ArrayList<Key> keys = CollectionUtils.newArrayList(inKeys);
+ Collections.sort(keys, EMOJI_KEY_COMPARATOR);
+ final int pageCount = (keys.size() - 1) / maxPageCount + 1;
final Key[][] retval = new Key[pageCount][maxPageCount];
- for (int i = 0; i < keys.length; ++i) {
- retval[i / maxPageCount][i % maxPageCount] = keys[i];
+ for (int i = 0; i < keys.size(); ++i) {
+ retval[i / maxPageCount][i % maxPageCount] = keys.get(i);
}
return retval;
}
@@ -447,12 +463,14 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
final ImageView iconView = (ImageView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_icon, null);
iconView.setImageResource(mEmojiCategory.getCategoryIcon(categoryId));
+ iconView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId));
tspec.setIndicator(iconView);
}
if (mEmojiCategory.getCategoryLabel(categoryId) != null) {
final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_label, null);
textView.setText(mEmojiCategory.getCategoryLabel(categoryId));
+ textView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId));
textView.setTextColor(mTabLabelColor);
tspec.setIndicator(textView);
}
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 4fd3bac2f..f646a03c2 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -25,6 +25,9 @@ import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.CoordinateUtils;
+import java.util.Collections;
+import java.util.List;
+
/**
* Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
* consists of rows of keys.
@@ -74,10 +77,10 @@ public class Keyboard {
/** Maximum column for more keys keyboard */
public final int mMaxMoreKeysKeyboardColumn;
- /** Array of keys and icons in this keyboard */
- private final Key[] mKeys;
- public final Key[] mShiftKeys;
- public final Key[] mAltCodeKeysWhileTyping;
+ /** List of keys in this keyboard */
+ private final List<Key> mSortedKeys;
+ public final List<Key> mShiftKeys;
+ public final List<Key> mAltCodeKeysWhileTyping;
public final KeyboardIconsSet mIconsSet;
private final SparseArray<Key> mKeyCache = CollectionUtils.newSparseArray();
@@ -100,15 +103,16 @@ public class Keyboard {
mTopPadding = params.mTopPadding;
mVerticalGap = params.mVerticalGap;
- mKeys = params.mKeys.toArray(new Key[params.mKeys.size()]);
- mShiftKeys = params.mShiftKeys.toArray(new Key[params.mShiftKeys.size()]);
- mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray(
- new Key[params.mAltCodeKeysWhileTyping.size()]);
+ mSortedKeys = Collections.unmodifiableList(
+ CollectionUtils.newArrayList(params.mSortedKeys));
+ mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
+ mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
mIconsSet = params.mIconsSet;
mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(),
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
- mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection);
+ mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys,
+ params.mTouchPositionCorrection);
mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
}
@@ -127,7 +131,7 @@ public class Keyboard {
mTopPadding = keyboard.mTopPadding;
mVerticalGap = keyboard.mVerticalGap;
- mKeys = keyboard.mKeys;
+ mSortedKeys = keyboard.mSortedKeys;
mShiftKeys = keyboard.mShiftKeys;
mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping;
mIconsSet = keyboard.mIconsSet;
@@ -152,17 +156,14 @@ public class Keyboard {
return mProximityInfo;
}
- public Key[] getKeys() {
- return mKeys;
- }
-
- public Key getKeyFromOutputText(final String outputText) {
- for (final Key key : getKeys()) {
- if (outputText.equals(key.getOutputText())) {
- return key;
- }
- }
- return null;
+ /**
+ * Return the sorted list of keys of this keyboard.
+ * The keys are sorted from top-left to bottom-right order.
+ * The list may contain {@link Spacer} object as well.
+ * @return the sorted unmodifiable list of {@link Key}s of this keyboard.
+ */
+ public List<Key> getSortedKeys() {
+ return mSortedKeys;
}
public Key getKey(final int code) {
@@ -175,7 +176,7 @@ public class Keyboard {
return mKeyCache.valueAt(index);
}
- for (final Key key : getKeys()) {
+ for (final Key key : getSortedKeys()) {
if (key.getCode() == code) {
mKeyCache.put(code, key);
return key;
@@ -191,7 +192,7 @@ public class Keyboard {
return true;
}
- for (final Key key : getKeys()) {
+ for (final Key key : getSortedKeys()) {
if (key == aKey) {
mKeyCache.put(key.getCode(), key);
return true;
@@ -209,10 +210,10 @@ public class Keyboard {
* Returns the array of the keys that are closest to the given point.
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
- * @return the array of the nearest keys to the given point. If the given
+ * @return the list of the nearest keys to the given point. If the given
* point is out of range, then an array of size zero is returned.
*/
- public Key[] getNearestKeys(final int x, final int y) {
+ public List<Key> getNearestKeys(final int x, final int y) {
// Avoid dead pixels at edges of the keyboard
final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 18e51d392..8ca00b005 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -289,7 +289,7 @@ public class KeyboardView extends View {
// TODO: Confirm if it's really required to draw all keys when hardware acceleration is on.
if (drawAllKeys || isHardwareAccelerated) {
// Draw all keys.
- for (final Key key : mKeyboard.getKeys()) {
+ for (final Key key : mKeyboard.getSortedKeys()) {
onDrawKey(key, canvas, paint);
}
} else {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
index abff202b7..5a9d4755f 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
@@ -43,7 +43,7 @@ public final class MoreKeysDetector extends KeyDetector {
Key nearestKey = null;
int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
- for (final Key key : keyboard.getKeys()) {
+ for (final Key key : keyboard.getSortedKeys()) {
final int dist = key.squaredDistanceToEdge(touchX, touchY);
if (dist < nearestDist) {
nearestKey = key;
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index a0316696c..3746d5b79 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -22,9 +22,13 @@ import android.util.Log;
import com.android.inputmethod.keyboard.internal.TouchPositionCorrection;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.JniUtils;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
public class ProximityInfo {
private static final String TAG = ProximityInfo.class.getSimpleName();
@@ -34,7 +38,7 @@ public class ProximityInfo {
public static final int MAX_PROXIMITY_CHARS_SIZE = 16;
/** Number of key widths from current touch point to search for nearest keys. */
private static final float SEARCH_DISTANCE = 1.2f;
- private static final Key[] EMPTY_KEY_ARRAY = new Key[0];
+ private static final List<Key> EMPTY_KEY_LIST = Collections.emptyList();
private static final float DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS = 0.15f;
private final int mGridWidth;
@@ -47,13 +51,13 @@ public class ProximityInfo {
private final int mKeyboardHeight;
private final int mMostCommonKeyWidth;
private final int mMostCommonKeyHeight;
- private final Key[] mKeys;
- private final Key[][] mGridNeighbors;
+ private final List<Key> mSortedKeys;
+ private final List<Key>[] mGridNeighbors;
private final String mLocaleStr;
ProximityInfo(final String localeStr, final int gridWidth, final int gridHeight,
final int minWidth, final int height, final int mostCommonKeyWidth,
- final int mostCommonKeyHeight, final Key[] keys,
+ final int mostCommonKeyHeight, final List<Key> sortedKeys,
final TouchPositionCorrection touchPositionCorrection) {
if (TextUtils.isEmpty(localeStr)) {
mLocaleStr = "";
@@ -69,8 +73,8 @@ public class ProximityInfo {
mKeyboardHeight = height;
mMostCommonKeyHeight = mostCommonKeyHeight;
mMostCommonKeyWidth = mostCommonKeyWidth;
- mKeys = keys;
- mGridNeighbors = new Key[mGridSize][];
+ mSortedKeys = sortedKeys;
+ mGridNeighbors = new List[mGridSize];
if (minWidth == 0 || height == 0) {
// No proximity required. Keyboard might be more keys keyboard.
return;
@@ -99,7 +103,7 @@ public class ProximityInfo {
return key.getCode() >= Constants.CODE_SPACE;
}
- private static int getProximityInfoKeysCount(final Key[] keys) {
+ private static int getProximityInfoKeysCount(final List<Key> keys) {
int count = 0;
for (final Key key : keys) {
if (needsProximityInfo(key)) {
@@ -110,14 +114,14 @@ public class ProximityInfo {
}
private long createNativeProximityInfo(final TouchPositionCorrection touchPositionCorrection) {
- final Key[][] gridNeighborKeys = mGridNeighbors;
+ final List<Key>[] gridNeighborKeys = mGridNeighbors;
final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
Arrays.fill(proximityCharsArray, Constants.NOT_A_CODE);
for (int i = 0; i < mGridSize; ++i) {
- final int proximityCharsLength = gridNeighborKeys[i].length;
+ final int proximityCharsLength = gridNeighborKeys[i].size();
int infoIndex = i * MAX_PROXIMITY_CHARS_SIZE;
for (int j = 0; j < proximityCharsLength; ++j) {
- final Key neighborKey = gridNeighborKeys[i][j];
+ final Key neighborKey = gridNeighborKeys[i].get(j);
// Excluding from proximityCharsArray
if (!needsProximityInfo(neighborKey)) {
continue;
@@ -142,8 +146,8 @@ public class ProximityInfo {
}
}
- final Key[] keys = mKeys;
- final int keyCount = getProximityInfoKeysCount(keys);
+ final List<Key> sortedKeys = mSortedKeys;
+ final int keyCount = getProximityInfoKeysCount(sortedKeys);
final int[] keyXCoordinates = new int[keyCount];
final int[] keyYCoordinates = new int[keyCount];
final int[] keyWidths = new int[keyCount];
@@ -153,8 +157,8 @@ public class ProximityInfo {
final float[] sweetSpotCenterYs;
final float[] sweetSpotRadii;
- for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
- final Key key = keys[keyIndex];
+ for (int infoIndex = 0, keyIndex = 0; keyIndex < sortedKeys.size(); keyIndex++) {
+ final Key key = sortedKeys.get(keyIndex);
// Excluding from key coordinate arrays
if (!needsProximityInfo(key)) {
continue;
@@ -177,8 +181,8 @@ public class ProximityInfo {
final int rows = touchPositionCorrection.getRows();
final float defaultRadius = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS
* (float)Math.hypot(mMostCommonKeyWidth, mMostCommonKeyHeight);
- for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
- final Key key = keys[keyIndex];
+ for (int infoIndex = 0, keyIndex = 0; keyIndex < sortedKeys.size(); keyIndex++) {
+ final Key key = sortedKeys.get(keyIndex);
// Excluding from touch position correction arrays
if (!needsProximityInfo(key)) {
continue;
@@ -240,7 +244,7 @@ public class ProximityInfo {
private void computeNearestNeighbors() {
final int defaultWidth = mMostCommonKeyWidth;
- final int keyCount = mKeys.length;
+ final int keyCount = mSortedKeys.size();
final int gridSize = mGridNeighbors.length;
final int threshold = (int) (defaultWidth * SEARCH_DISTANCE);
final int thresholdSquared = threshold * threshold;
@@ -259,7 +263,7 @@ public class ProximityInfo {
final int[] neighborCountPerCell = new int[gridSize];
final int halfCellWidth = mCellWidth / 2;
final int halfCellHeight = mCellHeight / 2;
- for (final Key key : mKeys) {
+ for (final Key key : mSortedKeys) {
if (key.isSpacer()) continue;
/* HOW WE PRE-SELECT THE CELLS (iterate over only the relevant cells, instead of all of them)
@@ -353,9 +357,13 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get
}
for (int i = 0; i < gridSize; ++i) {
- final int base = i * keyCount;
- mGridNeighbors[i] =
- Arrays.copyOfRange(neighborsFlatBuffer, base, base + neighborCountPerCell[i]);
+ final int indexStart = i * keyCount;
+ final int indexEnd = indexStart + neighborCountPerCell[i];
+ final ArrayList<Key> neighbords = CollectionUtils.newArrayList(indexEnd - indexStart);
+ for (int index = indexStart; index < indexEnd; index++) {
+ neighbords.add(neighborsFlatBuffer[index]);
+ }
+ mGridNeighbors[i] = Collections.unmodifiableList(neighbords);
}
}
@@ -369,7 +377,7 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get
if (primaryKeyCode > Constants.CODE_SPACE) {
dest[index++] = primaryKeyCode;
}
- final Key[] nearestKeys = getNearestKeys(x, y);
+ final List<Key> nearestKeys = getNearestKeys(x, y);
for (Key key : nearestKeys) {
if (index >= destLength) {
break;
@@ -385,9 +393,9 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get
}
}
- public Key[] getNearestKeys(final int x, final int y) {
+ public List<Key> getNearestKeys(final int x, final int y) {
if (mGridNeighbors == null) {
- return EMPTY_KEY_ARRAY;
+ return EMPTY_KEY_LIST;
}
if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) {
int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth);
@@ -395,6 +403,6 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get
return mGridNeighbors[index];
}
}
- return EMPTY_KEY_ARRAY;
+ return EMPTY_KEY_LIST;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index e2fd39017..397c098ce 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -30,6 +30,7 @@ import com.android.inputmethod.latin.utils.JsonUtils;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
@@ -50,7 +51,7 @@ public class DynamicGridKeyboard extends Keyboard {
private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
private final ArrayDeque<Key> mPendingKeys = CollectionUtils.newArrayDeque();
- private Key[] mCachedGridKeys;
+ private List<Key> mCachedGridKeys;
public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard,
final int maxKeyCount, final int categoryId) {
@@ -66,7 +67,7 @@ public class DynamicGridKeyboard extends Keyboard {
}
private Key getTemplateKey(final int code) {
- for (final Key key : super.getKeys()) {
+ for (final Key key : super.getSortedKeys()) {
if (key.getCode() == code) {
return key;
}
@@ -146,9 +147,10 @@ public class DynamicGridKeyboard extends Keyboard {
private static Key getKeyByCode(final Collection<DynamicGridKeyboard> keyboards,
final int code) {
for (final DynamicGridKeyboard keyboard : keyboards) {
- final Key key = keyboard.getKey(code);
- if (key != null) {
- return key;
+ for (final Key key : keyboard.getSortedKeys()) {
+ if (key.getCode() == code) {
+ return key;
+ }
}
}
return null;
@@ -156,10 +158,11 @@ public class DynamicGridKeyboard extends Keyboard {
private static Key getKeyByOutputText(final Collection<DynamicGridKeyboard> keyboards,
final String outputText) {
- for (final DynamicGridKeyboard kbd : keyboards) {
- final Key key = kbd.getKeyFromOutputText(outputText);
- if (key != null) {
- return key;
+ for (final DynamicGridKeyboard keyboard : keyboards) {
+ for (final Key key : keyboard.getSortedKeys()) {
+ if (outputText.equals(key.getOutputText())) {
+ return key;
+ }
}
}
return null;
@@ -205,20 +208,22 @@ public class DynamicGridKeyboard extends Keyboard {
}
@Override
- public Key[] getKeys() {
+ public List<Key> getSortedKeys() {
synchronized (mLock) {
if (mCachedGridKeys != null) {
return mCachedGridKeys;
}
- mCachedGridKeys = mGridKeys.toArray(new Key[mGridKeys.size()]);
+ final ArrayList<Key> cachedKeys = CollectionUtils.newArrayList(mGridKeys.size());
+ cachedKeys.addAll(mGridKeys);
+ mCachedGridKeys = Collections.unmodifiableList(cachedKeys);
return mCachedGridKeys;
}
}
@Override
- public Key[] getNearestKeys(final int x, final int y) {
+ public List<Key> getNearestKeys(final int x, final int y) {
// TODO: Calculate the nearest key index in mGridKeys from x and y.
- return getKeys();
+ return getSortedKeys();
}
static final class GridKey extends Key {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
index 153391eed..a61a79b85 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
@@ -24,6 +24,8 @@ import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.SortedSet;
import java.util.TreeSet;
public class KeyboardParams {
@@ -58,7 +60,8 @@ public class KeyboardParams {
public int GRID_WIDTH;
public int GRID_HEIGHT;
- public final TreeSet<Key> mKeys = CollectionUtils.newTreeSet(); // ordered set
+ // Keys are sorted from top-left to bottom-right order.
+ public final SortedSet<Key> mSortedKeys = new TreeSet<Key>(ROW_COLUMN_COMPARATOR);
public final ArrayList<Key> mShiftKeys = CollectionUtils.newArrayList();
public final ArrayList<Key> mAltCodeKeysWhileTyping = CollectionUtils.newArrayList();
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
@@ -75,8 +78,20 @@ public class KeyboardParams {
public final TouchPositionCorrection mTouchPositionCorrection =
new TouchPositionCorrection();
+ // Comparator to sort {@link Key}s from top-left to bottom-right order.
+ private static final Comparator<Key> ROW_COLUMN_COMPARATOR = new Comparator<Key>() {
+ @Override
+ public int compare(final Key lhs, final Key rhs) {
+ if (lhs.getY() < rhs.getY()) return -1;
+ if (lhs.getY() > rhs.getY()) return 1;
+ if (lhs.getX() < rhs.getX()) return -1;
+ if (lhs.getX() > rhs.getX()) return 1;
+ return 0;
+ }
+ };
+
protected void clearKeys() {
- mKeys.clear();
+ mSortedKeys.clear();
mShiftKeys.clear();
clearHistogram();
}
@@ -88,7 +103,7 @@ public class KeyboardParams {
// Ignore zero width {@link Spacer}.
return;
}
- mKeys.add(key);
+ mSortedKeys.add(key);
if (isSpacer) {
return;
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index e9b8431e7..a351ee974 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -262,7 +262,7 @@ public final class BinaryDictionary extends Dictionary {
final int inputSize;
if (!isGesture) {
inputSize = composer.copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount(
- mInputCodePoints, MAX_WORD_LENGTH);
+ mInputCodePoints);
if (inputSize < 0) {
return null;
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
index 7cb218fbe..0b6258a7f 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -421,7 +421,19 @@ public class DictionaryFacilitatorForSuggest {
final String suggestionLowerCase = suggestion.toLowerCase(dictionaries.mLocale);
final String secondWord;
if (wasAutoCapitalized) {
- secondWord = suggestionLowerCase;
+ if (isValidWord(suggestion, false /* ignoreCase */)
+ && !isValidWord(suggestionLowerCase, false /* ignoreCase */)) {
+ // If the word was auto-capitalized and exists only as a capitalized word in the
+ // dictionary, then we must not downcase it before registering it. For example,
+ // the name of the contacts in start-of-sentence position would come here with the
+ // wasAutoCapitalized flag: if we downcase it, we'd register a lower-case version
+ // of that contact's name which would end up popping in suggestions.
+ secondWord = suggestion;
+ } else {
+ // If however the word is not in the dictionary, or exists as a lower-case word
+ // only, then we consider that was a lower-case word that had been auto-capitalized.
+ secondWord = suggestionLowerCase;
+ }
} else {
// HACK: We'd like to avoid adding the capitalized form of common words to the User
// History dictionary in order to avoid suggesting them until the dictionary
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 1fdb8d16c..81b02c396 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -237,7 +237,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Otherwise, we'll do it when we can.
latinIme.mKeyboardSwitcher.loadKeyboard(latinIme.getCurrentInputEditorInfo(),
settingsValues, latinIme.getCurrentAutoCapsState(),
- latinIme.getCurrentAutoCapsState());
+ latinIme.getCurrentRecapitalizeState());
}
break;
}
@@ -501,7 +501,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
- registerReceiver(mReceiver, filter);
+ registerReceiver(mConnectivityAndRingerModeChangeReceiver, filter);
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -630,7 +630,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void onDestroy() {
mInputLogic.mSuggest.mDictionaryFacilitator.closeDictionaries();
mSettings.onDestroy();
- unregisterReceiver(mReceiver);
+ unregisterReceiver(mConnectivityAndRingerModeChangeReceiver);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.getInstance().onDestroy();
}
@@ -645,6 +645,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@UsedForTesting
public void recycle() {
+ unregisterReceiver(mDictionaryPackInstallReceiver);
+ unregisterReceiver(mDictionaryDumpBroadcastReceiver);
+ unregisterReceiver(mConnectivityAndRingerModeChangeReceiver);
mInputLogic.recycle();
}
@@ -816,9 +819,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
// effort to work around this bug.
mInputLogic.mConnection.tryFixLyingCursorPosition();
- if (isDifferentTextField) {
- mHandler.postResumeSuggestions();
- }
+ mHandler.postResumeSuggestions();
canReachInputConnection = true;
}
@@ -1635,7 +1636,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// boolean onKeyMultiple(final int keyCode, final int count, final KeyEvent event);
// receive ringer mode change and network state change.
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mConnectivityAndRingerModeChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 1268e5aac..d755195f2 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -129,22 +129,25 @@ public final class WordComposer {
* -1 is returned.
*
* @param destination the array of ints.
- * @param maxSize the size of the array.
* @return the number of copied code points.
*/
public int copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount(
- final int[] destination, final int maxSize) {
- final int i = mTypedWordCache.length() - 1 - trailingSingleQuotesCount();
- if (i < 0) {
+ final int[] destination) {
+ // lastIndex is exclusive
+ final int lastIndex = mTypedWordCache.length() - trailingSingleQuotesCount();
+ if (lastIndex <= 0) {
// The string is empty or contains only single quotes.
return 0;
}
- final int codePointSize = Character.codePointCount(mTypedWordCache, 0, i);
- if (codePointSize > maxSize) {
+
+ // The following function counts the number of code points in the text range which begins
+ // at index 0 and extends to the character at lastIndex.
+ final int codePointSize = Character.codePointCount(mTypedWordCache, 0, lastIndex);
+ if (codePointSize > destination.length) {
return -1;
}
return StringUtils.copyCodePointsAndReturnCodePointCount(destination, mTypedWordCache, 0,
- i + 1, true /* downCase */);
+ lastIndex, true /* downCase */);
}
public boolean isSingleLetter() {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 491d98074..f1f906042 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -1284,6 +1284,10 @@ public final class InputLogic {
|| !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
// If no suggestions are requested, don't try restarting suggestions.
|| !settingsValues.isSuggestionsRequested()
+ // If we are currently in a batch input, we must not resume suggestions, or the result
+ // of the batch input will replace the new composition. This may happen in the corner case
+ // that the app moves the cursor on its own accord during a batch input.
+ || mInputLogicHandler.isInBatchInput()
// If the cursor is not touching a word, or if there is a selection, return right away.
|| mConnection.hasSelection()
// If we don't know the cursor location, return.
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
index 64bba681f..9dbe2c38b 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
@@ -110,6 +110,10 @@ class InputLogicHandler implements Handler.Callback {
}
}
+ public boolean isInBatchInput() {
+ return mInBatchInput;
+ }
+
/**
* Fetch suggestions corresponding to an update of a batch input.
* @param batchPointers the updated pointers, including the part that was passed last time.
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 3cdd07361..a0793b133 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -240,6 +240,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
if (TextUtils.isEmpty(importantNoticeTitle)) {
return false;
}
+ if (isShowingMoreSuggestionPanel()) {
+ dismissMoreSuggestionsPanel();
+ }
mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, importantNoticeTitle);
mStripVisibilityGroup.showImportantNoticeStrip();
mImportantNoticeStrip.setOnClickListener(this);
diff --git a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
index ee9718ad3..ed502ed3d 100644
--- a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
@@ -47,8 +47,13 @@ public class ExecutorUtils {
public static void shutdownAllExecutors() {
synchronized(sExecutorMap) {
for (final PrioritizedSerialExecutor executor : sExecutorMap.values()) {
- executor.shutdown();
- sExecutorMap.remove(executor);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ executor.shutdown();
+ sExecutorMap.remove(executor);
+ }
+ });
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/utils/RunInLocale.java b/java/src/com/android/inputmethod/latin/utils/RunInLocale.java
index 2c9e3b191..1ea16e6ef 100644
--- a/java/src/com/android/inputmethod/latin/utils/RunInLocale.java
+++ b/java/src/com/android/inputmethod/latin/utils/RunInLocale.java
@@ -30,25 +30,23 @@ public abstract class RunInLocale<T> {
* Execute {@link #job(Resources)} method in specified system locale exclusively.
*
* @param res the resources to use.
- * @param newLocale the locale to change to.
+ * @param newLocale the locale to change to. Run in system locale if null.
* @return the value returned from {@link #job(Resources)}.
*/
public T runInLocale(final Resources res, final Locale newLocale) {
synchronized (sLockForRunInLocale) {
final Configuration conf = res.getConfiguration();
- final Locale oldLocale = conf.locale;
- final boolean needsChange = (newLocale != null && !newLocale.equals(oldLocale));
+ if (newLocale == null || newLocale.equals(conf.locale)) {
+ return job(res);
+ }
+ final Locale savedLocale = conf.locale;
try {
- if (needsChange) {
- conf.locale = newLocale;
- res.updateConfiguration(conf, null);
- }
+ conf.locale = newLocale;
+ res.updateConfiguration(conf, null);
return job(res);
} finally {
- if (needsChange) {
- conf.locale = oldLocale;
- res.updateConfiguration(conf, null);
- }
+ conf.locale = savedLocale;
+ res.updateConfiguration(conf, null);
}
}
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index b1f54c0b4..d907dd1b0 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -1362,7 +1362,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
kid.navigateNext(), kid.navigatePrevious(), kid.mClobberSettingsKey,
isPasswordView, kid.mSupportsSwitchingToShortcutIme, kid.mHasShortcutKey,
kid.mLanguageSwitchKeyEnabled, kid.isMultiLine(), keyboard.mOccupiedWidth,
- keyboard.mOccupiedHeight, keyboard.getKeys());
+ keyboard.mOccupiedHeight, keyboard.getSortedKeys());
}
/**