aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/res/values-en/additional-proximitychars.xml62
-rw-r--r--java/res/values/additional-proximitychars.xml23
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java41
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java36
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java50
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java19
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java4
7 files changed, 210 insertions, 25 deletions
diff --git a/java/res/values-en/additional-proximitychars.xml b/java/res/values-en/additional-proximitychars.xml
new file mode 100644
index 000000000..0e1276796
--- /dev/null
+++ b/java/res/values-en/additional-proximitychars.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string-array name="additional_proximitychars">
+ <!-- Empty entry terminates the proximity chars array. -->
+
+ <!-- Additional proximity chars for a -->
+ <item>a</item>
+ <item>e</item>
+ <item>i</item>
+ <item>o</item>
+ <item>u</item>
+ <item></item>
+ <!-- Additional proximity chars for e -->
+ <item>e</item>
+ <item>a</item>
+ <item>i</item>
+ <item>o</item>
+ <item>u</item>
+ <item></item>
+ <!-- Additional proximity chars for i -->
+ <item>i</item>
+ <item>a</item>
+ <item>e</item>
+ <item>o</item>
+ <item>u</item>
+ <item></item>
+ <!-- Additional proximity chars for o -->
+ <item>o</item>
+ <item>a</item>
+ <item>e</item>
+ <item>i</item>
+ <item>u</item>
+ <item></item>
+ <!-- Additional proximity chars for u -->
+ <item>u</item>
+ <item>a</item>
+ <item>e</item>
+ <item>i</item>
+ <item>o</item>
+ <item></item>
+ </string-array>
+
+</resources> \ No newline at end of file
diff --git a/java/res/values/additional-proximitychars.xml b/java/res/values/additional-proximitychars.xml
new file mode 100644
index 000000000..03d10d5d8
--- /dev/null
+++ b/java/res/values/additional-proximitychars.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="additional_proximitychars">
+ </string-array>
+</resources>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 0d271625b..bff491ffd 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -19,12 +19,14 @@ package com.android.inputmethod.keyboard;
import android.util.Log;
import java.util.Arrays;
+import java.util.List;
public class KeyDetector {
private static final String TAG = KeyDetector.class.getSimpleName();
private static final boolean DEBUG = false;
public static final int NOT_A_CODE = -1;
+ private static final int ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE = 2;
private final int mKeyHysteresisDistanceSquared;
@@ -154,8 +156,9 @@ public class KeyDetector {
return distances.length;
}
- private void getNearbyKeyCodes(final int[] allCodes) {
+ private void getNearbyKeyCodes(final int primaryCode, final int[] allCodes) {
final Key[] neighborKeys = mNeighborKeys;
+ final int maxCodesSize = allCodes.length;
// allCodes[0] should always have the key code even if it is a non-letter key.
if (neighborKeys[0] == null) {
@@ -164,7 +167,7 @@ public class KeyDetector {
}
int numCodes = 0;
- for (int j = 0; j < neighborKeys.length && numCodes < allCodes.length; j++) {
+ for (int j = 0; j < neighborKeys.length && numCodes < maxCodesSize; j++) {
final Key key = neighborKeys[j];
if (key == null)
break;
@@ -174,6 +177,38 @@ public class KeyDetector {
continue;
allCodes[numCodes++] = code;
}
+ if (maxCodesSize <= numCodes) {
+ return;
+ }
+ if (primaryCode != NOT_A_CODE) {
+ final List<Integer> additionalChars =
+ mKeyboard.getAdditionalProximityChars().get(primaryCode);
+ if (additionalChars == null || additionalChars.size() == 0) {
+ return;
+ }
+ int currentCodesSize = numCodes;
+ allCodes[numCodes++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
+ if (maxCodesSize <= numCodes) {
+ return;
+ }
+ // TODO: This is O(N^2). Assuming additionalChars.size() is up to 4 or 5.
+ for (int i = 0; i < additionalChars.size(); ++i) {
+ final int additionalChar = additionalChars.get(i);
+ boolean contains = false;
+ for (int j = 0; j < currentCodesSize; ++j) {
+ if (additionalChar == allCodes[j]) {
+ contains = true;
+ break;
+ }
+ }
+ if (!contains) {
+ allCodes[numCodes++] = additionalChar;
+ if (maxCodesSize <= numCodes) {
+ return;
+ }
+ }
+ }
+ }
}
/**
@@ -205,7 +240,7 @@ public class KeyDetector {
}
if (allCodes != null && allCodes.length > 0) {
- getNearbyKeyCodes(allCodes);
+ getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes);
if (DEBUG) {
Log.d(TAG, "x=" + x + " y=" + y
+ " primary=" + printableCode(primaryKey)
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 6653dec4b..10e0a5b01 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -38,10 +39,12 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -130,6 +133,8 @@ public class Keyboard {
private final ProximityInfo mProximityInfo;
+ public final Map<Integer, List<Integer>> mAdditionalProximityChars;
+
public Keyboard(Params params) {
mId = params.mId;
mThemeId = params.mThemeId;
@@ -146,10 +151,12 @@ public class Keyboard {
mKeys = Collections.unmodifiableSet(params.mKeys);
mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys);
mIconsSet = params.mIconsSet;
+ mAdditionalProximityChars = params.mAdditionalProximityChars;
mProximityInfo = new ProximityInfo(
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
- mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection);
+ mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection,
+ params.mAdditionalProximityChars);
}
public ProximityInfo getProximityInfo() {
@@ -227,6 +234,9 @@ public class Keyboard {
public final Set<Key> mKeys = new HashSet<Key>();
public final Set<Key> mShiftKeys = new HashSet<Key>();
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
+ // TODO: Should be in Key instead of Keyboard.Params?
+ public final Map<Integer, List<Integer>> mAdditionalProximityChars =
+ new HashMap<Integer, List<Integer>>();
public KeyboardSet.KeysCache mKeysCache;
@@ -358,6 +368,10 @@ public class Keyboard {
return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
}
+ public Map<Integer, List<Integer>> getAdditionalProximityChars() {
+ return mAdditionalProximityChars;
+ }
+
public static String printableCode(int code) {
switch (code) {
case CODE_SHIFT: return "shift";
@@ -614,6 +628,7 @@ public class Keyboard {
mParams = params;
setTouchPositionCorrectionData(context, params);
+ setAdditionalProximityChars(context, params);
params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
@@ -636,6 +651,25 @@ public class Keyboard {
params.mTouchPositionCorrection.load(data);
}
+ private static void setAdditionalProximityChars(Context context, Params params) {
+ final String[] additionalChars =
+ context.getResources().getStringArray(R.array.additional_proximitychars);
+ int currentPrimaryIndex = 0;
+ for (int i = 0; i < additionalChars.length; ++i) {
+ final String additionalChar = additionalChars[i];
+ if (TextUtils.isEmpty(additionalChar)) {
+ currentPrimaryIndex = 0;
+ } else if (currentPrimaryIndex == 0) {
+ currentPrimaryIndex = additionalChar.charAt(0);
+ params.mAdditionalProximityChars.put(
+ currentPrimaryIndex, new ArrayList<Integer>());
+ } else if (currentPrimaryIndex != 0) {
+ final int c = additionalChar.charAt(0);
+ params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c);
+ }
+ }
+ }
+
public void setAutoGenerate(KeyboardSet.KeysCache keysCache) {
mParams.mKeysCache = keysCache;
}
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index c1dae0601..2d1a0083d 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -24,6 +24,9 @@ import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
public class ProximityInfo {
@@ -44,7 +47,8 @@ public class ProximityInfo {
private final Key[][] mGridNeighbors;
ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth,
- int keyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection) {
+ int keyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection,
+ Map<Integer, List<Integer>> additionalProximityChars) {
mGridWidth = gridWidth;
mGridHeight = gridHeight;
mGridSize = mGridWidth * mGridHeight;
@@ -58,20 +62,20 @@ public class ProximityInfo {
// No proximity required. Keyboard might be mini keyboard.
return;
}
- computeNearestNeighbors(keyWidth, keys, touchPositionCorrection);
+ computeNearestNeighbors(keyWidth, keys, touchPositionCorrection, additionalProximityChars);
}
public static ProximityInfo createDummyProximityInfo() {
- return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptySet(), null);
+ return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key> emptySet(),
+ null, Collections.<Integer, List<Integer>> emptyMap());
}
public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) {
final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo();
spellCheckerProximityInfo.mNativeProximityInfo =
spellCheckerProximityInfo.setProximityInfoNative(
- SpellCheckerProximityInfo.ROW_SIZE,
- 480, 300, 11, 3, proximity,
- 0, null, null, null, null, null, null, null, null);
+ SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 11, 3, proximity, 0,
+ null, null, null, null, null, null, null, null);
return spellCheckerProximityInfo;
}
@@ -79,11 +83,13 @@ public class ProximityInfo {
static {
Utils.loadNativeLibrary();
}
+
private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth,
int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray,
int keyCount, int[] keyXCoordinates, int[] keyYCoordinates,
int[] keyWidths, int[] keyHeights, int[] keyCharCodes,
float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii);
+
private native void releaseProximityInfoNative(long nativeProximityInfo);
private final void setProximityInfo(Key[][] gridNeighborKeys, int keyboardWidth,
@@ -138,7 +144,7 @@ public class ProximityInfo {
final float radius = touchPositionCorrection.mRadii[row];
sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
- sweetSpotRadii[i] = radius * (float)Math.sqrt(
+ sweetSpotRadii[i] = radius * (float) Math.sqrt(
hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
}
}
@@ -168,7 +174,12 @@ public class ProximityInfo {
}
private void computeNearestNeighbors(int defaultWidth, Set<Key> keys,
- TouchPositionCorrection touchPositionCorrection) {
+ TouchPositionCorrection touchPositionCorrection,
+ Map<Integer, List<Integer>> additionalProximityChars) {
+ final Map<Integer, Key> keyCodeMap = new HashMap<Integer, Key>();
+ for (final Key key : keys) {
+ keyCodeMap.put(key.mCode, key);
+ }
final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE);
final int threshold = thresholdBase * thresholdBase;
// Round-up so we don't have any pixels outside the grid
@@ -186,6 +197,27 @@ public class ProximityInfo {
neighborKeys[count++] = key;
}
}
+ int currentCodesSize = count;
+ for (int i = 0; i < currentCodesSize; ++i) {
+ final int c = neighborKeys[i].mCode;
+ final List<Integer> additionalChars = additionalProximityChars.get(c);
+ if (additionalChars == null || additionalChars.size() == 0) {
+ continue;
+ }
+ for (int j = 0; j < additionalChars.size(); ++j) {
+ final int additionalChar = additionalChars.get(j);
+ boolean contains = false;
+ for (int k = 0; k < count; ++k) {
+ if(additionalChar == neighborKeys[k].mCode) {
+ contains = true;
+ break;
+ }
+ }
+ if (!contains) {
+ neighborKeys[count++] = keyCodeMap.get(additionalChar);
+ }
+ }
+ }
mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] =
Arrays.copyOfRange(neighborKeys, 0, count);
}
@@ -199,7 +231,7 @@ public class ProximityInfo {
return EMPTY_KEY_ARRAY;
}
if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) {
- int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth);
+ int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth);
if (index < mGridSize) {
return mGridNeighbors[index];
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 19cd16ad2..1bc55a583 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -872,13 +872,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// turn this flag on in succession and both onUpdateSelection() calls arrive after
// the second one - the first call successfully avoids this test, but the second one
// enters. For the moment we rely on candidatesCleared to further reduce the impact.
- if (SPACE_STATE_WEAK == mSpaceState) {
- // Test for no WEAK_SPACE action because there is a race condition that may end up
- // in coming here on a normal key press. We set this to NONE because after
- // a cursor move, we don't want the suggestion strip to swap the space with the
- // newly inserted punctuation.
- mSpaceState = SPACE_STATE_NONE;
- }
+
+ // We set this to NONE because after a cursor move, we don't want the space
+ // state-related special processing to kick in.
+ mSpaceState = SPACE_STATE_NONE;
+
if (((mWordComposer.isComposingWord())
|| mVoiceProxy.isVoiceInputHighlighted())
&& (selectionChanged || candidatesCleared)) {
@@ -2221,9 +2219,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// be needed, but it's there just in case something went wrong.
final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0);
if (!". ".equals(textBeforeCursor)) {
- // We should not have come here if we aren't just after a ". ".
- throw new RuntimeException("Tried to revert double-space combo but we didn't find "
+ // Theoretically we should not be coming here if there isn't ". " before the
+ // cursor, but the application may be changing the text while we are typing, so
+ // anything goes. We should not crash.
+ Log.d(TAG, "Tried to revert double-space combo but we didn't find "
+ "\". \" just before the cursor.");
+ return false;
}
ic.beginBatchEdit();
ic.deleteSurroundingText(2, 0);
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 230c2916b..bd244b913 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,8 +16,6 @@
package com.android.inputmethod.latin;
-import android.text.TextUtils;
-
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.KeyDetector;
import com.android.inputmethod.keyboard.Keyboard;
@@ -33,7 +31,7 @@ public class WordComposer {
public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
public static final int NOT_A_COORDINATE = -1;
- final int N = BinaryDictionary.MAX_WORD_LENGTH;
+ final static int N = BinaryDictionary.MAX_WORD_LENGTH;
private ArrayList<int[]> mCodes;
private int[] mXCoordinates;