aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java27
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java18
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java32
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java108
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java63
-rw-r--r--java/src/com/android/inputmethod/latin/CoordinateUtils.java10
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java1
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java2
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java2
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java22
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java41
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java22
12 files changed, 252 insertions, 96 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index d7cb5aa92..992282bf9 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -135,7 +135,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Preview placer view
private final PreviewPlacerView mPreviewPlacerView;
- private final int[] mCoordinates = CoordinateUtils.newInstance();
+ private final int[] mOriginCoords = CoordinateUtils.newInstance();
// Key preview
private static final int PREVIEW_ALPHA = 240;
@@ -833,10 +833,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// In transient state.
return;
}
- final int[] viewOrigin = CoordinateUtils.newInstance();
- getLocationInWindow(viewOrigin);
+ getLocationInWindow(mOriginCoords);
final DisplayMetrics dm = getResources().getDisplayMetrics();
- if (CoordinateUtils.y(viewOrigin) < dm.heightPixels / 4) {
+ if (CoordinateUtils.y(mOriginCoords) < dm.heightPixels / 4) {
// In transient state.
return;
}
@@ -851,11 +850,21 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView");
} else {
windowContentView.addView(mPreviewPlacerView);
- mPreviewPlacerView.setKeyboardViewGeometry(
- CoordinateUtils.x(viewOrigin), CoordinateUtils.y(viewOrigin), width, height);
+ mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height);
}
}
+ @Override
+ public void showSlidingKeyInputPreview(final PointerTracker tracker) {
+ locatePreviewPlacerView();
+ mPreviewPlacerView.showSlidingKeyInputPreview(tracker);
+ }
+
+ @Override
+ public void dismissSlidingKeyInputPreview() {
+ mPreviewPlacerView.dismissSlidingKeyInputPreview();
+ }
+
public void showGestureFloatingPreviewText(final String gestureFloatingPreviewText) {
locatePreviewPlacerView();
mPreviewPlacerView.setGestureFloatingPreviewText(gestureFloatingPreviewText);
@@ -937,13 +946,13 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// The distance between the top edge of the parent key and the bottom of the visible part
// of the key preview background.
previewParams.mPreviewVisibleOffset = mPreviewOffset - previewText.getPaddingBottom();
- getLocationInWindow(mCoordinates);
+ getLocationInWindow(mOriginCoords);
// The key preview is horizontally aligned with the center of the visible part of the
// parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
// the left/right background is used if such background is specified.
final int statePosition;
int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2
- + CoordinateUtils.x(mCoordinates);
+ + CoordinateUtils.x(mOriginCoords);
if (previewX < 0) {
previewX = 0;
statePosition = STATE_LEFT;
@@ -956,7 +965,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// The key preview is placed vertically above the top edge of the parent key with an
// arbitrary offset.
final int previewY = key.mY - previewHeight + mPreviewOffset
- + CoordinateUtils.y(mCoordinates);
+ + CoordinateUtils.y(mOriginCoords);
if (background != null) {
final int hasMoreKeys = (key.mMoreKeys != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL;
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 7e9e3ce1a..b9ce4fb1f 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -49,6 +49,7 @@ import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.keyboard.internal.KeyDrawParams;
import com.android.inputmethod.keyboard.internal.TouchScreenRegulator;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.DebugSettings;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
@@ -672,12 +673,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mMoreKeysPanel = moreKeysPanel;
mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
+ final int[] lastCoords = CoordinateUtils.newInstance();
+ tracker.getLastCoordinates(lastCoords);
final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview();
// The more keys keyboard is usually horizontally aligned with the center of the parent key.
// If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
// keys keyboard is placed at the touch point of the parent key.
final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled)
- ? tracker.getLastX()
+ ? CoordinateUtils.x(lastCoords)
: parentKey.mX + parentKey.mWidth / 2;
// The more keys keyboard is usually vertically aligned with the top edge of the parent key
// (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically
@@ -687,8 +690,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final int pointY = parentKey.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset;
moreKeysPanel.showMoreKeysPanel(
this, this, pointX, pointY, mMoreKeysWindow, mKeyboardActionListener);
- final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
- final int translatedY = moreKeysPanel.translateY(tracker.getLastY());
+ final int translatedX = moreKeysPanel.translateX(CoordinateUtils.x(lastCoords));
+ final int translatedY = moreKeysPanel.translateY(CoordinateUtils.y(lastCoords));
tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel);
dimEntireKeyboard(true);
return true;
@@ -788,10 +791,11 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
} else if (pointerCount == 2 && oldPointerCount == 1) {
// Single-touch to multi-touch transition.
// Send an up event for the last pointer.
- final int lastX = tracker.getLastX();
- final int lastY = tracker.getLastY();
- mOldKey = tracker.getKeyOn(lastX, lastY);
- tracker.onUpEvent(lastX, lastY, eventTime);
+ final int[] lastCoords = CoordinateUtils.newInstance();
+ mOldKey = tracker.getKeyOn(
+ CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords));
+ tracker.onUpEvent(
+ CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime);
} else if (pointerCount == 1 && oldPointerCount == 1) {
tracker.processMotionEvent(action, x, y, eventTime, this);
} else {
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index c3cf49f3b..d9a520917 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -28,6 +28,7 @@ import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
@@ -80,6 +81,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public void invalidateKey(Key key);
public void showKeyPreview(PointerTracker tracker);
public void dismissKeyPreview(PointerTracker tracker);
+ public void showSlidingKeyInputPreview(PointerTracker tracker);
+ public void dismissSlidingKeyInputPreview();
public void showGesturePreviewTrail(PointerTracker tracker, boolean isOldestTracker);
}
@@ -296,6 +299,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// The position and time at which first down event occurred.
private long mDownTime;
+ private int[] mDownCoordinates = CoordinateUtils.newInstance();
private long mUpTime;
// The current key where this pointer is.
@@ -540,6 +544,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return mIsInSlidingKeyInput;
}
+ public boolean isInSlidingKeyInputFromModifier() {
+ return mIsInSlidingKeyInputFromModifier;
+ }
+
public Key getKey() {
return mCurrentKey;
}
@@ -642,20 +650,21 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return mGestureStrokeWithPreviewPoints;
}
- public int getLastX() {
- return mLastX;
- }
-
- public int getLastY() {
- return mLastY;
+ public void getLastCoordinates(final int[] outCoords) {
+ CoordinateUtils.set(outCoords, mLastX, mLastY);
}
public long getDownTime() {
return mDownTime;
}
+ public void getDownCoordinates(final int[] outCoords) {
+ CoordinateUtils.copy(outCoords, mDownCoordinates);
+ }
+
private Key onDownKey(final int x, final int y, final long eventTime) {
mDownTime = eventTime;
+ CoordinateUtils.set(mDownCoordinates, x, y);
mBogusMoveEventDetector.onDownKey();
return onMoveToNewKey(onMoveKeyInternal(x, y), x, y);
}
@@ -721,6 +730,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (key != null) {
updateBatchInput(eventTime);
}
+ if (mIsTrackingCanceled) {
+ return;
+ }
mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
}
@@ -759,6 +771,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
}
+ if (mIsTrackingCanceled) {
+ return;
+ }
mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
}
@@ -867,6 +882,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
private void resetSlidingKeyInput() {
mIsInSlidingKeyInput = false;
mIsInSlidingKeyInputFromModifier = false;
+ mDrawingProxy.dismissSlidingKeyInputPreview();
}
private void onGestureMoveEvent(final int x, final int y, final long eventTime,
@@ -1061,6 +1077,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
slideOutFromOldKey(oldKey, x, y);
}
}
+ mDrawingProxy.showSlidingKeyInputPreview(this);
}
public void onUpEvent(final int x, final int y, final long eventTime) {
@@ -1087,7 +1104,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
@Override
public void onPhantomUpEvent(final long eventTime) {
if (DEBUG_EVENT) {
- printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime);
+ printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime);
}
onUpEventInternal(eventTime);
cancelTracking();
@@ -1134,6 +1151,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
public void onLongPressed() {
+ resetSlidingKeyInput();
cancelTracking();
setReleasedKeyGraphics(mCurrentKey);
sPointerTrackerQueue.remove(this);
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index ed01f3458..b5ba98d85 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -99,6 +99,7 @@ public final class ProximityInfo {
JniUtils.loadNativeLibrary();
}
+ // TODO: Stop passing proximityCharsArray
private native long setProximityInfoNative(
String locale, int maxProximityCharsSize, int displayWidth,
int displayHeight, int gridWidth, int gridHeight,
@@ -109,22 +110,56 @@ public final class ProximityInfo {
private native void releaseProximityInfoNative(long nativeProximityInfo);
- private final long createNativeProximityInfo(
- final TouchPositionCorrection touchPositionCorrection) {
+ private static boolean needsProximityInfo(final Key key) {
+ // Don't include special keys into ProximityInfo.
+ return key.mCode >= Constants.CODE_SPACE;
+ }
+
+ private static int getProximityInfoKeysCount(final Key[] keys) {
+ int count = 0;
+ for (final Key key : keys) {
+ if (needsProximityInfo(key)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private long createNativeProximityInfo(final TouchPositionCorrection touchPositionCorrection) {
final Key[][] gridNeighborKeys = mGridNeighbors;
- final int keyboardWidth = mKeyboardMinWidth;
- final int keyboardHeight = mKeyboardHeight;
- final Key[] keys = mKeys;
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;
+ int infoIndex = i * MAX_PROXIMITY_CHARS_SIZE;
for (int j = 0; j < proximityCharsLength; ++j) {
- proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] =
- gridNeighborKeys[i][j].mCode;
+ final Key neighborKey = gridNeighborKeys[i][j];
+ // Excluding from proximityCharsArray
+ if (!needsProximityInfo(neighborKey)) {
+ continue;
+ }
+ proximityCharsArray[infoIndex] = neighborKey.mCode;
+ infoIndex++;
}
}
- final int keyCount = keys.length;
+ if (DEBUG) {
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < mGridSize; i++) {
+ sb.setLength(0);
+ for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE; j++) {
+ final int code = proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j];
+ if (code == Constants.NOT_A_CODE) {
+ break;
+ }
+ if (sb.length() > 0) sb.append(" ");
+ sb.append(Constants.printableCode(code));
+ }
+ Log.d(TAG, "proxmityChars["+i+"]: " + sb);
+ }
+ }
+
+ final Key[] keys = mKeys;
+ final int keyCount = getProximityInfoKeysCount(keys);
final int[] keyXCoordinates = new int[keyCount];
final int[] keyYCoordinates = new int[keyCount];
final int[] keyWidths = new int[keyCount];
@@ -134,13 +169,18 @@ public final class ProximityInfo {
final float[] sweetSpotCenterYs;
final float[] sweetSpotRadii;
- for (int i = 0; i < keyCount; ++i) {
- final Key key = keys[i];
- keyXCoordinates[i] = key.mX;
- keyYCoordinates[i] = key.mY;
- keyWidths[i] = key.mWidth;
- keyHeights[i] = key.mHeight;
- keyCharCodes[i] = key.mCode;
+ for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+ final Key key = keys[keyIndex];
+ // Excluding from key coordinate arrays
+ if (!needsProximityInfo(key)) {
+ continue;
+ }
+ keyXCoordinates[infoIndex] = key.mX;
+ keyYCoordinates[infoIndex] = key.mY;
+ keyWidths[infoIndex] = key.mWidth;
+ keyHeights[infoIndex] = key.mHeight;
+ keyCharCodes[infoIndex] = key.mCode;
+ infoIndex++;
}
if (touchPositionCorrection != null && touchPositionCorrection.isValid()) {
@@ -153,28 +193,36 @@ public final class ProximityInfo {
final int rows = touchPositionCorrection.getRows();
final float defaultRadius = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS
* (float)Math.hypot(mMostCommonKeyWidth, mMostCommonKeyHeight);
- for (int i = 0; i < keyCount; i++) {
- final Key key = keys[i];
+ for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+ final Key key = keys[keyIndex];
+ // Excluding from touch position correction arrays
+ if (!needsProximityInfo(key)) {
+ continue;
+ }
final Rect hitBox = key.mHitBox;
- sweetSpotCenterXs[i] = hitBox.exactCenterX();
- sweetSpotCenterYs[i] = hitBox.exactCenterY();
- sweetSpotRadii[i] = defaultRadius;
+ sweetSpotCenterXs[infoIndex] = hitBox.exactCenterX();
+ sweetSpotCenterYs[infoIndex] = hitBox.exactCenterY();
+ sweetSpotRadii[infoIndex] = defaultRadius;
final int row = hitBox.top / mMostCommonKeyHeight;
if (row < rows) {
final int hitBoxWidth = hitBox.width();
final int hitBoxHeight = hitBox.height();
final float hitBoxDiagonal = (float)Math.hypot(hitBoxWidth, hitBoxHeight);
- sweetSpotCenterXs[i] += touchPositionCorrection.getX(row) * hitBoxWidth;
- sweetSpotCenterYs[i] += touchPositionCorrection.getY(row) * hitBoxHeight;
- sweetSpotRadii[i] = touchPositionCorrection.getRadius(row) * hitBoxDiagonal;
+ sweetSpotCenterXs[infoIndex] +=
+ touchPositionCorrection.getX(row) * hitBoxWidth;
+ sweetSpotCenterYs[infoIndex] +=
+ touchPositionCorrection.getY(row) * hitBoxHeight;
+ sweetSpotRadii[infoIndex] =
+ touchPositionCorrection.getRadius(row) * hitBoxDiagonal;
}
if (DEBUG) {
Log.d(TAG, String.format(
- " [%2d] row=%d x/y/r=%7.2f/%7.2f/%5.2f %s code=%s", i, row,
- sweetSpotCenterXs[i], sweetSpotCenterYs[i], sweetSpotRadii[i],
- (row < rows ? "correct" : "default"),
+ " [%2d] row=%d x/y/r=%7.2f/%7.2f/%5.2f %s code=%s", infoIndex, row,
+ sweetSpotCenterXs[infoIndex], sweetSpotCenterYs[infoIndex],
+ sweetSpotRadii[infoIndex], (row < rows ? "correct" : "default"),
Constants.printableCode(key.mCode)));
}
+ infoIndex++;
}
} else {
sweetSpotCenterXs = sweetSpotCenterYs = sweetSpotRadii = null;
@@ -183,11 +231,11 @@ public final class ProximityInfo {
}
}
+ // TODO: Stop passing proximityCharsArray
return setProximityInfoNative(mLocaleStr, MAX_PROXIMITY_CHARS_SIZE,
- keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth,
- proximityCharsArray,
- keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
- sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+ mKeyboardMinWidth, mKeyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth,
+ proximityCharsArray, keyCount, keyXCoordinates, keyYCoordinates, keyWidths,
+ keyHeights, keyCharCodes, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
}
public long getNativeProximityInfo() {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index 0d44ecdff..bc734b08d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -36,6 +36,7 @@ import android.widget.RelativeLayout;
import com.android.inputmethod.keyboard.PointerTracker;
import com.android.inputmethod.keyboard.internal.GesturePreviewTrail.Params;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
@@ -47,8 +48,7 @@ public final class PreviewPlacerView extends RelativeLayout {
private final float mGestureFloatingPreviewVerticalPadding;
private final float mGestureFloatingPreviewRoundRadius;
- private int mKeyboardViewOriginX;
- private int mKeyboardViewOriginY;
+ private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance();
private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails =
CollectionUtils.newSparseArray();
@@ -68,11 +68,14 @@ public final class PreviewPlacerView extends RelativeLayout {
private final int mGestureFloatingPreviewTextHeight;
// {@link RectF} is needed for {@link Canvas#drawRoundRect(RectF, float, float, Paint)}.
private final RectF mGestureFloatingPreviewRectangle = new RectF();
- private int mLastPointerX;
- private int mLastPointerY;
+ private final int[] mLastPointerCoords = CoordinateUtils.newInstance();
private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' };
private boolean mDrawsGestureFloatingPreviewText;
+ private boolean mShowSlidingKeyInputPreview;
+ private final int[] mRubberBandFrom = CoordinateUtils.newInstance();
+ private final int[] mRubberBandTo = CoordinateUtils.newInstance();
+
private final DrawingHandler mDrawingHandler;
private static final class DrawingHandler extends StaticInnerHandlerWrapper<PreviewPlacerView> {
@@ -168,9 +171,8 @@ public final class PreviewPlacerView extends RelativeLayout {
setLayerType(LAYER_TYPE_HARDWARE, layerPaint);
}
- public void setKeyboardViewGeometry(final int x, final int y, final int w, final int h) {
- mKeyboardViewOriginX = x;
- mKeyboardViewOriginY = y;
+ public void setKeyboardViewGeometry(final int[] originCoords, final int w, final int h) {
+ CoordinateUtils.copy(mKeyboardViewOrigin, originCoords);
mOffscreenOffsetY = (int)(h * GestureStroke.EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
mOffscreenWidth = w;
mOffscreenHeight = mOffscreenOffsetY + h;
@@ -186,8 +188,7 @@ public final class PreviewPlacerView extends RelativeLayout {
final boolean needsToUpdateLastPointer =
isOldestTracker && mDrawsGestureFloatingPreviewText;
if (needsToUpdateLastPointer) {
- mLastPointerX = tracker.getLastX();
- mLastPointerY = tracker.getLastY();
+ tracker.getLastCoordinates(mLastPointerCoords);
}
if (mDrawsGesturePreviewTrail) {
@@ -208,6 +209,21 @@ public final class PreviewPlacerView extends RelativeLayout {
}
}
+ public void showSlidingKeyInputPreview(final PointerTracker tracker) {
+ if (!tracker.isInSlidingKeyInputFromModifier()) {
+ mShowSlidingKeyInputPreview = false;
+ return;
+ }
+ tracker.getDownCoordinates(mRubberBandFrom);
+ tracker.getLastCoordinates(mRubberBandTo);
+ mShowSlidingKeyInputPreview = true;
+ invalidate();
+ }
+
+ public void dismissSlidingKeyInputPreview() {
+ mShowSlidingKeyInputPreview = false;
+ }
+
@Override
protected void onDetachedFromWindow() {
freeOffscreenBuffer();
@@ -234,6 +250,8 @@ public final class PreviewPlacerView extends RelativeLayout {
@Override
public void onDraw(final Canvas canvas) {
super.onDraw(canvas);
+ final int originX = CoordinateUtils.x(mKeyboardViewOrigin);
+ final int originY = CoordinateUtils.y(mKeyboardViewOrigin);
if (mDrawsGesturePreviewTrail) {
mayAllocateOffscreenBuffer();
// Draw gesture trails to offscreen buffer.
@@ -241,11 +259,11 @@ public final class PreviewPlacerView extends RelativeLayout {
mOffscreenCanvas, mGesturePaint, mOffscreenDirtyRect);
// Transfer offscreen buffer to screen.
if (!mOffscreenDirtyRect.isEmpty()) {
- final int offsetY = mKeyboardViewOriginY - mOffscreenOffsetY;
- canvas.translate(mKeyboardViewOriginX, offsetY);
+ final int offsetY = originY - mOffscreenOffsetY;
+ canvas.translate(originX, offsetY);
canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect,
mGesturePaint);
- canvas.translate(-mKeyboardViewOriginX, -offsetY);
+ canvas.translate(-originX, -offsetY);
// Note: Defer clearing the dirty rectangle here because we will get cleared
// rectangle on the canvas.
}
@@ -254,9 +272,14 @@ public final class PreviewPlacerView extends RelativeLayout {
}
}
if (mDrawsGestureFloatingPreviewText) {
- canvas.translate(mKeyboardViewOriginX, mKeyboardViewOriginY);
+ canvas.translate(originX, originY);
drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
- canvas.translate(-mKeyboardViewOriginX, -mKeyboardViewOriginY);
+ canvas.translate(-originX, -originY);
+ }
+ if (mShowSlidingKeyInputPreview) {
+ canvas.translate(originX, originY);
+ drawSlidingKeyInputPreview(canvas);
+ canvas.translate(-originX, -originY);
}
}
@@ -317,8 +340,6 @@ public final class PreviewPlacerView extends RelativeLayout {
final Paint paint = mTextPaint;
final RectF rectangle = mGestureFloatingPreviewRectangle;
- // TODO: Figure out how we should deal with the floating preview text with multiple moving
- // fingers.
// Paint the round rectangle background.
final int textHeight = mGestureFloatingPreviewTextHeight;
@@ -328,9 +349,11 @@ public final class PreviewPlacerView extends RelativeLayout {
final float rectWidth = textWidth + hPad * 2.0f;
final float rectHeight = textHeight + vPad * 2.0f;
final int canvasWidth = canvas.getWidth();
- final float rectX = Math.min(Math.max(mLastPointerX - rectWidth / 2.0f, 0.0f),
+ final float rectX = Math.min(
+ Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f),
canvasWidth - rectWidth);
- final float rectY = mLastPointerY - mGestureFloatingPreviewTextOffset - rectHeight;
+ final float rectY = CoordinateUtils.y(mLastPointerCoords)
+ - mGestureFloatingPreviewTextOffset - rectHeight;
rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight);
final float round = mGestureFloatingPreviewRoundRadius;
paint.setColor(mGestureFloatingPreviewColor);
@@ -341,4 +364,8 @@ public final class PreviewPlacerView extends RelativeLayout {
final float textY = rectY + vPad + textHeight;
canvas.drawText(gestureFloatingPreviewText, textX, textY, paint);
}
+
+ private void drawSlidingKeyInputPreview(final Canvas canvas) {
+ // TODO: Implement rubber band preview
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/CoordinateUtils.java b/java/src/com/android/inputmethod/latin/CoordinateUtils.java
index cd3177299..af270e1e4 100644
--- a/java/src/com/android/inputmethod/latin/CoordinateUtils.java
+++ b/java/src/com/android/inputmethod/latin/CoordinateUtils.java
@@ -36,4 +36,14 @@ public final class CoordinateUtils {
public static int y(final int[] coords) {
return coords[INDEX_Y];
}
+
+ public static void set(final int[] coords, final int x, final int y) {
+ coords[INDEX_X] = x;
+ coords[INDEX_Y] = y;
+ }
+
+ public static void copy(final int[] destination, final int[] source) {
+ destination[INDEX_X] = source[INDEX_X];
+ destination[INDEX_Y] = source[INDEX_Y];
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 8519ad31d..d8e536745 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1177,6 +1177,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private boolean maybeDoubleSpace() {
if (!mCurrentSettings.mCorrectionEnabled) return false;
+ if (!mCurrentSettings.mUseDoubleSpacePeriod) return false;
if (!mHandler.isAcceptingDoubleSpaces()) return false;
final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0);
if (lastThree != null && lastThree.length() == 3
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index fdad5430a..7a73cade3 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -60,6 +60,8 @@ public final class Settings extends InputMethodSettingsFragment
"last_user_dictionary_write_time";
public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings";
public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict";
+ public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD =
+ "pref_key_use_double_space_period";
public static final String PREF_SHOW_LANGUAGE_SWITCH_KEY =
"pref_show_language_switch_key";
public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST =
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 8de64c1c9..a23876722 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -75,6 +75,7 @@ public final class SettingsValues {
@SuppressWarnings("unused") // TODO: Use this
private final String mKeyPreviewPopupDismissDelayRawValue;
public final boolean mUseContactsDict;
+ public final boolean mUseDoubleSpacePeriod;
// Use bigrams to predict the next word when there is no input for it yet
public final boolean mBigramPredictionEnabled;
@SuppressWarnings("unused") // TODO: Use this
@@ -154,6 +155,7 @@ public final class SettingsValues {
Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout)));
mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
+ mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true);
mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue);
mBigramPredictionEnabled = isBigramPredictionEnabled(prefs, res);
mVibrationDurationSettingsRawValue =
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 49b98863f..2f146f86c 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -438,15 +438,23 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE;
final int len = text.length();
int capsCount = 1;
+ int letterCount = 1;
for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) {
- if (1 != capsCount && i != capsCount) break;
- if (Character.isUpperCase(text.codePointAt(i))) ++capsCount;
+ if (1 != capsCount && letterCount != capsCount) break;
+ final int codePoint = text.codePointAt(i);
+ if (Character.isUpperCase(codePoint)) {
+ ++capsCount;
+ ++letterCount;
+ } else if (Character.isLetter(codePoint)) {
+ // We need to discount non-letters since they may not be upper-case, but may
+ // still be part of a word (e.g. single quote or dash, as in "IT'S" or "FULL-TIME")
+ ++letterCount;
+ }
}
- // We know the first char is upper case. So we want to test if either everything
- // else is lower case, or if everything else is upper case. If the string is
- // exactly one char long, then we will arrive here with capsCount 1, and this is
- // correct, too.
+ // We know the first char is upper case. So we want to test if either every letter other
+ // than the first is lower case, or if they are all upper case. If the string is exactly
+ // one char long, then we will arrive here with letterCount 1, and this is correct, too.
if (1 == capsCount) return CAPITALIZE_FIRST;
- return (len == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE);
+ return (letterCount == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE);
}
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index a8f323999..470943be1 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -28,9 +28,11 @@ import android.view.textservice.TextInfo;
import com.android.inputmethod.compat.SuggestionsInfoCompatUtils;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.LocaleUtils;
-import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.StringUtils;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.WordComposer;
import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer;
import java.util.ArrayList;
@@ -188,6 +190,35 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
return (letterCount * 4 < length * 3);
}
+ /**
+ * Helper method to test valid capitalizations of a word.
+ *
+ * If the "text" is lower-case, we test only the exact string.
+ * If the "Text" is capitalized, we test the exact string "Text" and the lower-cased
+ * version of it "text".
+ * If the "TEXT" is fully upper case, we test the exact string "TEXT", the lower-cased
+ * version of it "text" and the capitalized version of it "Text".
+ */
+ private boolean isInDictForAnyCapitalization(final Dictionary dict, final String text,
+ final int capitalizeType) {
+ // If the word is in there as is, then it's in the dictionary. If not, we'll test lower
+ // case versions, but only if the word is not already all-lower case or mixed case.
+ if (dict.isValidWord(text)) return true;
+ if (AndroidSpellCheckerService.CAPITALIZE_NONE == capitalizeType) return false;
+
+ // If we come here, we have a capitalized word (either First- or All-).
+ // Downcase the word and look it up again. If the word is only capitalized, we
+ // tested all possibilities, so if it's still negative we can return false.
+ final String lowerCaseText = text.toLowerCase(mLocale);
+ if (dict.isValidWord(lowerCaseText)) return true;
+ if (AndroidSpellCheckerService.CAPITALIZE_FIRST == capitalizeType) return false;
+
+ // If the lower case version is not in the dictionary, it's still possible
+ // that we have an all-caps version of a word that needs to be capitalized
+ // according to the dictionary. E.g. "GERMANS" only exists in the dictionary as "Germans".
+ return dict.isValidWord(StringUtils.toTitleCase(lowerCaseText, mLocale));
+ }
+
// Note : this must be reentrant
/**
* Gets a list of suggestions for a specific string. This returns a list of possible
@@ -272,13 +303,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
suggestionStr.length(), suggestion.mScore);
}
- isInDict = dictInfo.mDictionary.isValidWord(text);
- if (!isInDict && AndroidSpellCheckerService.CAPITALIZE_NONE != capitalizeType) {
- // We want to test the word again if it's all caps or first caps only.
- // If it's fully down, we already tested it, if it's mixed case, we don't
- // want to test a lowercase version of it.
- isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale));
- }
+ isInDict = isInDictForAnyCapitalization(dictInfo.mDictionary, text, capitalizeType);
} finally {
if (null != dictInfo) {
if (!mDictionaryPool.offer(dictInfo)) {
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index fe31039e3..3443b7a7a 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -925,18 +925,20 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_onWindowHidden(final int savedSelectionStart,
final int savedSelectionEnd, final InputConnection ic) {
if (ic != null) {
- // Capture the TextView contents. This will trigger onUpdateSelection(), so we
- // set sLatinIMEExpectingUpdateSelection so that when onUpdateSelection() is called,
- // it can tell that it was generated by the logging code, and not by the user, and
- // therefore keep user-visible state as is.
- ic.beginBatchEdit();
- ic.performContextMenuAction(android.R.id.selectAll);
- CharSequence charSequence = ic.getSelectedText(0);
- ic.setSelection(savedSelectionStart, savedSelectionEnd);
- ic.endBatchEdit();
- sLatinIMEExpectingUpdateSelection = true;
final Object[] values = new Object[2];
if (OUTPUT_ENTIRE_BUFFER) {
+ // Capture the TextView contents. This will trigger onUpdateSelection(), so we
+ // set sLatinIMEExpectingUpdateSelection so that when onUpdateSelection() is called,
+ // it can tell that it was generated by the logging code, and not by the user, and
+ // therefore keep user-visible state as is.
+ ic.beginBatchEdit();
+ ic.performContextMenuAction(android.R.id.selectAll);
+ CharSequence charSequence = ic.getSelectedText(0);
+ if (savedSelectionStart != -1 && savedSelectionEnd != -1) {
+ ic.setSelection(savedSelectionStart, savedSelectionEnd);
+ }
+ ic.endBatchEdit();
+ sLatinIMEExpectingUpdateSelection = true;
if (TextUtils.isEmpty(charSequence)) {
values[0] = false;
values[1] = "";