diff options
Diffstat (limited to 'java/src')
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/PointerTracker.java | 47 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java | 135 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java | 34 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java (renamed from java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java) | 37 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java | 32 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/Settings.java | 8 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/SettingsValues.java | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java | 8 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/WordComposer.java | 9 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java | 127 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java | 195 |
11 files changed, 403 insertions, 231 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index a6439c46a..2bde8d2c5 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -23,7 +23,7 @@ import android.view.MotionEvent; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.keyboard.internal.GestureStroke; -import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewTrail; +import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.InputPointers; @@ -208,7 +208,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener.Adapter(); - private final GestureStrokeWithPreviewTrail mGestureStrokeWithPreviewTrail; + private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; public static void init(boolean hasDistinctMultitouch, boolean needsPhantomSuddenMoveEventHack) { @@ -293,7 +293,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { throw new NullPointerException(); } mPointerId = id; - mGestureStrokeWithPreviewTrail = new GestureStrokeWithPreviewTrail(id); + mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(id); setKeyDetectorInner(handler.getKeyDetector()); mListener = handler.getKeyboardActionListener(); mDrawingProxy = handler.getDrawingProxy(); @@ -392,7 +392,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { private void setKeyDetectorInner(final KeyDetector keyDetector) { mKeyDetector = keyDetector; mKeyboard = keyDetector.getKeyboard(); - mGestureStrokeWithPreviewTrail.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth); + mGestureStrokeWithPreviewPoints.setKeyboardGeometry(mKeyboard.mMostCommonKeyWidth); final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); if (newKey != mCurrentKey) { if (mDrawingProxy != null) { @@ -502,8 +502,8 @@ public class PointerTracker implements PointerTrackerQueue.Element { mDrawingProxy.invalidateKey(key); } - public GestureStrokeWithPreviewTrail getGestureStrokeWithPreviewTrail() { - return mGestureStrokeWithPreviewTrail; + public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { + return mGestureStrokeWithPreviewPoints; } public int getLastX() { @@ -544,8 +544,8 @@ public class PointerTracker implements PointerTrackerQueue.Element { return (sPointerTrackerQueue == null) ? 1 : sPointerTrackerQueue.size(); } - private void startBatchInput() { - if (sInGesture || !mGestureStrokeWithPreviewTrail.isStartOfAGesture()) { + private void mayStartBatchInput() { + if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { return; } if (DEBUG_LISTENER) { @@ -559,7 +559,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { private void updateBatchInput(final long eventTime) { synchronized (sAggregratedPointers) { - mGestureStrokeWithPreviewTrail.appendIncrementalBatchPoints(sAggregratedPointers); + mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers); final int size = sAggregratedPointers.getPointerSize(); if (size > sLastRecognitionPointSize && eventTime > sLastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME) { @@ -575,10 +575,10 @@ public class PointerTracker implements PointerTrackerQueue.Element { mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); } - private void endBatchInput() { + private void mayEndBatchInput() { synchronized (sAggregratedPointers) { - mGestureStrokeWithPreviewTrail.appendAllBatchPoints(sAggregratedPointers); - mGestureStrokeWithPreviewTrail.reset(); + mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); + mGestureStrokeWithPreviewPoints.reset(); if (getActivePointerTrackerCount() == 1) { if (DEBUG_LISTENER) { Log.d(TAG, "onEndBatchInput: batchPoints=" @@ -601,7 +601,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); - tracker.mGestureStrokeWithPreviewTrail.reset(); + tracker.mGestureStrokeWithPreviewPoints.reset(); } sAggregratedPointers.reset(); sLastRecognitionPointSize = 0; @@ -678,18 +678,21 @@ public class PointerTracker implements PointerTrackerQueue.Element { && mKeyboard.mId.isAlphabetKeyboard(); if (isAlphabetKeyboard && !mIsShowingMoreKeysPanel && key != null && Keyboard.isLetterCode(key.mCode)) { - mIsDetectingGesture = true; sGestureFirstDownTime = eventTime; - mGestureStrokeWithPreviewTrail.addPoint(x, y, 0, false /* isHistorical */); + onGestureDownEvent(x, y, eventTime); } } else if (sInGesture && activePointerTrackerCount > 1) { - mIsDetectingGesture = true; - final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime); - mGestureStrokeWithPreviewTrail.addPoint(x, y, elapsedTimeFromFirstDown, - false /* isHistorical */); + onGestureDownEvent(x, y, eventTime); } } + private void onGestureDownEvent(final int x, final int y, final long eventTime) { + mIsDetectingGesture = true; + final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime); + mGestureStrokeWithPreviewPoints.addPoint(x, y, elapsedTimeFromFirstDown, + false /* isHistorical */); + } + private void onDownEventInternal(final int x, final int y, final long eventTime) { Key key = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding @@ -726,8 +729,8 @@ public class PointerTracker implements PointerTrackerQueue.Element { final boolean isHistorical, final Key key) { final int gestureTime = (int)(eventTime - sGestureFirstDownTime); if (mIsDetectingGesture) { - mGestureStrokeWithPreviewTrail.addPoint(x, y, gestureTime, isHistorical); - startBatchInput(); + mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isHistorical); + mayStartBatchInput(); if (sInGesture && key != null) { updateBatchInput(eventTime); } @@ -919,7 +922,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { if (currentKey != null) { callListenerOnRelease(currentKey, currentKey.mCode, true); } - endBatchInput(); + mayEndBatchInput(); return; } // This event will be recognized as a regular code input. Clear unused possible batch points diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java index 4311fa775..699aaeaef 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java @@ -17,7 +17,9 @@ package com.android.inputmethod.keyboard.internal; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.Rect; +import android.graphics.RectF; import android.os.SystemClock; import com.android.inputmethod.latin.Constants; @@ -25,7 +27,7 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.ResizableIntArray; final class GesturePreviewTrail { - private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewTrail.PREVIEW_CAPACITY; + private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewPoints.PREVIEW_CAPACITY; private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); @@ -78,7 +80,7 @@ final class GesturePreviewTrail { ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark; } - public void addStroke(final GestureStrokeWithPreviewTrail stroke, final long downTime) { + public void addStroke(final GestureStrokeWithPreviewPoints stroke, final long downTime) { final int trailSize = mEventTimes.getLength(); stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates); if (mEventTimes.getLength() == trailSize) { @@ -116,6 +118,99 @@ final class GesturePreviewTrail { / params.mTrailLingerDuration, 0.0f); } + static final class WorkingSet { + // Input + // Previous point (P1) coordinates and trail radius. + public float p1x, p1y; + public float r1; + // Current point (P2) coordinates and trail radius. + public float p2x, p2y; + public float r2; + + // Output + // Closing point of arc at P1. + public float p1ax, p1ay; + // Opening point of arc at P1. + public float p1bx, p1by; + // Opening point of arc at P2. + public float p2ax, p2ay; + // Closing point of arc at P2. + public float p2bx, p2by; + // Start angle of the trail arcs. + public float aa; + // Sweep angle of the trail arc at P1. + public float a1; + public RectF arc1 = new RectF(); + // Sweep angle of the trail arc at P2. + public float a2; + public RectF arc2 = new RectF(); + } + + private static final float RIGHT_ANGLE = (float)(Math.PI / 2.0d); + private static final float RADIAN_TO_DEGREE = (float)(180.0d / Math.PI); + + private static boolean calculatePathPoints(final WorkingSet w) { + final float dx = w.p2x - w.p1x; + final float dy = w.p2y - w.p1y; + // Distance of the points. + final double l = Math.hypot(dx, dy); + if (Double.compare(0.0d, l) == 0) { + return false; + } + // Angle of the line p1-p2 + final float a = (float)Math.atan2(dy, dx); + // Difference of trail cap radius. + final float dr = w.r2 - w.r1; + // Variation of angle at trail cap. + final float ar = (float)Math.asin(dr / l); + // The start angle of trail cap arc at P1. + final float aa = a - (RIGHT_ANGLE + ar); + // The end angle of trail cap arc at P2. + final float ab = a + (RIGHT_ANGLE + ar); + final float cosa = (float)Math.cos(aa); + final float sina = (float)Math.sin(aa); + final float cosb = (float)Math.cos(ab); + final float sinb = (float)Math.sin(ab); + w.p1ax = w.p1x + w.r1 * cosa; + w.p1ay = w.p1y + w.r1 * sina; + w.p1bx = w.p1x + w.r1 * cosb; + w.p1by = w.p1y + w.r1 * sinb; + w.p2ax = w.p2x + w.r2 * cosa; + w.p2ay = w.p2y + w.r2 * sina; + w.p2bx = w.p2x + w.r2 * cosb; + w.p2by = w.p2y + w.r2 * sinb; + w.aa = aa * RADIAN_TO_DEGREE; + final float ar2degree = ar * 2.0f * RADIAN_TO_DEGREE; + w.a1 = -180.0f + ar2degree; + w.a2 = 180.0f + ar2degree; + w.arc1.set(w.p1x, w.p1y, w.p1x, w.p1y); + w.arc1.inset(-w.r1, -w.r1); + w.arc2.set(w.p2x, w.p2y, w.p2x, w.p2y); + w.arc2.inset(-w.r2, -w.r2); + return true; + } + + private static void createPath(final Path path, final WorkingSet w) { + path.rewind(); + // Trail cap at P1. + path.moveTo(w.p1x, w.p1y); + path.arcTo(w.arc1, w.aa, w.a1); + // Trail cap at P2. + path.moveTo(w.p2x, w.p2y); + path.arcTo(w.arc2, w.aa, w.a2); + // Two trapezoids connecting P1 and P2. + path.moveTo(w.p1ax, w.p1ay); + path.lineTo(w.p1x, w.p1y); + path.lineTo(w.p1bx, w.p1by); + path.lineTo(w.p2bx, w.p2by); + path.lineTo(w.p2x, w.p2y); + path.lineTo(w.p2ax, w.p2ay); + path.close(); + } + + private final WorkingSet mWorkingSet = new WorkingSet(); + private final Path mPath = new Path(); + /** * Draw gesture preview trail * @param canvas The canvas to draw the gesture preview trail @@ -147,30 +242,38 @@ final class GesturePreviewTrail { if (startIndex < trailSize) { paint.setColor(params.mTrailColor); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeCap(Paint.Cap.ROUND); - int lastX = getXCoordValue(xCoords[startIndex]); - int lastY = yCoords[startIndex]; - float maxWidth = getWidth(sinceDown - eventTimes[startIndex], params); + paint.setStyle(Paint.Style.FILL); + final Path path = mPath; + final WorkingSet w = mWorkingSet; + w.p1x = getXCoordValue(xCoords[startIndex]); + w.p1y = yCoords[startIndex]; + int lastTime = sinceDown - eventTimes[startIndex]; + float maxWidth = getWidth(lastTime, params); + w.r1 = maxWidth / 2.0f; // Initialize bounds rectangle. - outBoundsRect.set(lastX, lastY, lastX, lastY); + outBoundsRect.set((int)w.p1x, (int)w.p1y, (int)w.p1x, (int)w.p1y); for (int i = startIndex + 1; i < trailSize - 1; i++) { - final int x = xCoords[i]; - final int y = yCoords[i]; final int elapsedTime = sinceDown - eventTimes[i]; + w.p2x = getXCoordValue(xCoords[i]); + w.p2y = yCoords[i]; // Draw trail line only when the current point isn't a down point. - if (!isDownEventXCoord(x)) { + if (!isDownEventXCoord(xCoords[i])) { final int alpha = getAlpha(elapsedTime, params); paint.setAlpha(alpha); final float width = getWidth(elapsedTime, params); - paint.setStrokeWidth(width); - canvas.drawLine(lastX, lastY, x, y, paint); + w.r2 = width / 2.0f; + if (calculatePathPoints(w)) { + createPath(path, w); + canvas.drawPath(path, paint); + outBoundsRect.union((int)w.p2x, (int)w.p2y); + } // Take union for the bounds. - outBoundsRect.union(x, y); maxWidth = Math.max(maxWidth, width); } - lastX = getXCoordValue(x); - lastY = y; + w.p1x = w.p2x; + w.p1y = w.p2y; + w.r1 = w.r2; + lastTime = elapsedTime; } // Take care of trail line width. final int inset = -((int)maxWidth + 1); diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index 825134468..093a530d5 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -25,7 +25,6 @@ public class GestureStroke { private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private float mLength; - private float mAngle; private int mIncrementalRecognitionSize; private int mLastIncrementalBatchSize; private long mLastPointTime; @@ -40,15 +39,12 @@ public class GestureStroke { private static final int MIN_GESTURE_DURATION = 100; // msec private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f; private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; // dip/msec - private static final float GESTURE_RECOG_CURVATURE_THRESHOLD = (float)(Math.PI / 4.0f); - - private static final float DOUBLE_PI = (float)(2.0f * Math.PI); public GestureStroke(final int pointerId) { mPointerId = pointerId; } - public void setGestureSampleLength(final int keyWidth) { + public void setKeyboardGeometry(final int keyWidth) { // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? mMinGestureLength = (int)(keyWidth * MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH); mMinGestureSampleLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH); @@ -62,7 +58,6 @@ public class GestureStroke { public void reset() { mLength = 0; - mAngle = 0; mIncrementalRecognitionSize = 0; mLastIncrementalBatchSize = 0; mLastPointTime = 0; @@ -97,16 +92,6 @@ public class GestureStroke { mXCoordinates.add(x); mYCoordinates.add(y); mLength += dist; - final float angle = getAngle(lastX, lastY, x, y); - if (size > 1) { - final float curvature = getAngleDiff(angle, mAngle); - if (curvature > GESTURE_RECOG_CURVATURE_THRESHOLD) { - if (size > mIncrementalRecognitionSize) { - mIncrementalRecognitionSize = size; - } - } - } - mAngle = angle; } if (!isHistorical) { @@ -146,21 +131,4 @@ public class GestureStroke { // java.lang.Math due to the way the JIT optimizes java.lang.Math. return (float)Math.sqrt(dx * dx + dy * dy); } - - private static float getAngle(final int x1, final int y1, final int x2, final int y2) { - final int dx = x1 - x2; - final int dy = y1 - y2; - if (dx == 0 && dy == 0) return 0; - // Would it be faster to call atan2f() directly via JNI? Not sure about what the JIT - // does with Math.atan2(). - return (float)Math.atan2(dy, dx); - } - - private static float getAngleDiff(final float a1, final float a2) { - final float diff = Math.abs(a1 - a2); - if (diff > Math.PI) { - return DOUBLE_PI - diff; - } - return diff; - } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java index 6c1a9bc01..ce3914076 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.internal; import com.android.inputmethod.latin.ResizableIntArray; -public class GestureStrokeWithPreviewTrail extends GestureStroke { +public class GestureStrokeWithPreviewPoints extends GestureStroke { public static final int PREVIEW_CAPACITY = 256; private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY); @@ -26,7 +26,14 @@ public class GestureStrokeWithPreviewTrail extends GestureStroke { private int mStrokeId; private int mLastPreviewSize; - public GestureStrokeWithPreviewTrail(final int pointerId) { + private int mMinPreviewSampleLengthSquare; + private int mLastX; + private int mLastY; + + // TODO: Move this to resource. + private static final float MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH = 0.1f; + + public GestureStrokeWithPreviewPoints(final int pointerId) { super(pointerId); } @@ -49,11 +56,31 @@ public class GestureStrokeWithPreviewTrail extends GestureStroke { } @Override + public void setKeyboardGeometry(final int keyWidth) { + super.setKeyboardGeometry(keyWidth); + final float sampleLength = keyWidth * MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH; + mMinPreviewSampleLengthSquare = (int)(sampleLength * sampleLength); + } + + private boolean needsSampling(final int x, final int y) { + final int dx = x - mLastX; + final int dy = y - mLastY; + final boolean needsSampling = (dx * dx + dy * dy >= mMinPreviewSampleLengthSquare); + if (needsSampling) { + mLastX = x; + mLastY = y; + } + return needsSampling; + } + + @Override public void addPoint(final int x, final int y, final int time, final boolean isHistorical) { super.addPoint(x, y, time, isHistorical); - mPreviewEventTimes.add(time); - mPreviewXCoordinates.add(x); - mPreviewYCoordinates.add(y); + if (mPreviewEventTimes.getLength() == 0 || isHistorical || needsSampling(x, y)) { + mPreviewEventTimes.add(time); + mPreviewXCoordinates.add(x); + mPreviewYCoordinates.add(y); + } } public void appendPreviewStroke(final ResizableIntArray eventTimes, diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index 3a850096f..075a9bb0c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -189,22 +189,29 @@ public class PreviewPlacerView extends RelativeLayout { } public void invalidatePointer(final PointerTracker tracker, final boolean isOldestTracker) { - GesturePreviewTrail trail; - synchronized (mGesturePreviewTrails) { - trail = mGesturePreviewTrails.get(tracker.mPointerId); - if (trail == null) { - trail = new GesturePreviewTrail(); - mGesturePreviewTrails.put(tracker.mPointerId, trail); - } - } - trail.addStroke(tracker.getGestureStrokeWithPreviewTrail(), tracker.getDownTime()); - - if (isOldestTracker) { + final boolean needsToUpdateLastPointer = + isOldestTracker && mDrawsGestureFloatingPreviewText; + if (needsToUpdateLastPointer) { mLastPointerX = tracker.getLastX(); mLastPointerY = tracker.getLastY(); } + + if (mDrawsGesturePreviewTrail) { + GesturePreviewTrail trail; + synchronized (mGesturePreviewTrails) { + trail = mGesturePreviewTrails.get(tracker.mPointerId); + if (trail == null) { + trail = new GesturePreviewTrail(); + mGesturePreviewTrails.put(tracker.mPointerId, trail); + } + } + trail.addStroke(tracker.getGestureStrokeWithPreviewPoints(), tracker.getDownTime()); + } + // TODO: Should narrow the invalidate region. - invalidate(); + if (mDrawsGesturePreviewTrail || needsToUpdateLastPointer) { + invalidate(); + } } @Override @@ -262,6 +269,7 @@ public class PreviewPlacerView extends RelativeLayout { } public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) { + if (!mDrawsGestureFloatingPreviewText) return; mGestureFloatingPreviewText = gestureFloatingPreviewText; invalidate(); } diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 180f6c56f..c2dec2593 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -77,8 +77,8 @@ public class Settings extends InputMethodSettingsFragment public static final String PREF_KEYPRESS_SOUND_VOLUME = "pref_keypress_sound_volume"; public static final String PREF_GESTURE_PREVIEW_TRAIL = "pref_gesture_preview_trail"; - public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT = - "pref_gesture_floating_preview_text"; + public static final String PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT = + "pref_show_gesture_floating_preview_text"; public static final String PREF_INPUT_LANGUAGE = "input_language"; public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; @@ -207,7 +207,7 @@ public class Settings extends InputMethodSettingsFragment R.bool.config_gesture_input_enabled_by_build_config); final Preference gesturePreviewTrail = findPreference(PREF_GESTURE_PREVIEW_TRAIL); final Preference gestureFloatingPreviewText = findPreference( - PREF_GESTURE_FLOATING_PREVIEW_TEXT); + PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT); if (!gestureInputEnabledByBuildConfig) { miscSettings.removePreference(findPreference(PREF_GESTURE_INPUT)); miscSettings.removePreference(gesturePreviewTrail); @@ -304,7 +304,7 @@ public class Settings extends InputMethodSettingsFragment PREF_GESTURE_INPUT, true); setPreferenceEnabled(findPreference(PREF_GESTURE_PREVIEW_TRAIL), gestureInputEnabledByUser); - setPreferenceEnabled(findPreference(PREF_GESTURE_FLOATING_PREVIEW_TEXT), + setPreferenceEnabled(findPreference(PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT), gestureInputEnabledByUser); } } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 5e9c870d4..d9cf2700b 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -178,7 +178,7 @@ public final class SettingsValues { && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true); mGesturePreviewTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true); mGestureFloatingPreviewTextEnabled = prefs.getBoolean( - Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); + Settings.PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT, false); mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; mSuggestionVisibility = createSuggestionVisibility(res); } diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java index 550e4e58b..4a3d11aa1 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import android.util.Log; +import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; @@ -96,6 +97,11 @@ public class UserHistoryDictIOUtils { public void put(final byte b) { mBuffer[mPosition++] = b; } + + @Override + public int limit() { + return mBuffer.length; + } } /** @@ -162,7 +168,7 @@ public class UserHistoryDictIOUtils { final Map<Integer, ArrayList<PendingAttribute>> bigrams = CollectionUtils.newTreeMap(); try { - BinaryDictInputOutput.readUnigramsAndBigramsBinary(buffer, unigrams, frequencies, + BinaryDictIOUtils.readUnigramsAndBigramsBinary(buffer, unigrams, frequencies, bigrams); addWordsFromWordMap(unigrams, frequencies, bigrams, dict); } catch (IOException e) { diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 7785e3fb9..275ebf305 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -265,9 +265,12 @@ public class WordComposer { * @return true if all user typed chars are upper case, false otherwise */ public boolean isAllUpperCase() { - return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED - || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED - || (mCapsCount > 1) && (mCapsCount == size()); + if (size() <= 1) { + return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED + || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED; + } else { + return mCapsCount == size(); + } } public boolean wasShiftedNoLock() { diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java new file mode 100644 index 000000000..1a85e71ce --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin.makedict; + +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; +import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Map; +import java.util.Stack; + +public class BinaryDictIOUtils { + private static final boolean DBG = false; + + private static class Position { + public static final int NOT_READ_GROUPCOUNT = -1; + + public int mAddress; + public int mNumOfCharGroup; + public int mPosition; + public int mLength; + + public Position(int address, int length) { + mAddress = address; + mLength = length; + mNumOfCharGroup = NOT_READ_GROUPCOUNT; + } + } + + /** + * Tours all node without recursive call. + */ + private static void readUnigramsAndBigramsBinaryInner( + final FusionDictionaryBufferInterface buffer, final int headerSize, + final Map<Integer, String> words, final Map<Integer, Integer> frequencies, + final Map<Integer, ArrayList<PendingAttribute>> bigrams, + final FormatOptions formatOptions) { + int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1]; + + Stack<Position> stack = new Stack<Position>(); + int index = 0; + + Position initPos = new Position(headerSize, 0); + stack.push(initPos); + + while (!stack.empty()) { + Position p = stack.peek(); + + if (DBG) { + MakedictLog.d("read: address=" + p.mAddress + ", numOfCharGroup=" + + p.mNumOfCharGroup + ", position=" + p.mPosition + ", length=" + p.mLength); + } + + if (buffer.position() != p.mAddress) buffer.position(p.mAddress); + if (index != p.mLength) index = p.mLength; + + if (p.mNumOfCharGroup == Position.NOT_READ_GROUPCOUNT) { + p.mNumOfCharGroup = BinaryDictInputOutput.readCharGroupCount(buffer); + p.mAddress += BinaryDictInputOutput.getGroupCountSize(p.mNumOfCharGroup); + p.mPosition = 0; + } + + CharGroupInfo info = BinaryDictInputOutput.readCharGroup(buffer, + p.mAddress - headerSize, formatOptions); + for (int i = 0; i < info.mCharacters.length; ++i) { + pushedChars[index++] = info.mCharacters[i]; + } + p.mPosition++; + + if (info.mFrequency != FusionDictionary.CharGroup.NOT_A_TERMINAL) { // found word + words.put(info.mOriginalAddress, new String(pushedChars, 0, index)); + frequencies.put(info.mOriginalAddress, info.mFrequency); + if (info.mBigrams != null) bigrams.put(info.mOriginalAddress, info.mBigrams); + } + + if (p.mPosition == p.mNumOfCharGroup) { + stack.pop(); + } else { + // the node has more groups. + p.mAddress = buffer.position(); + } + + if (BinaryDictInputOutput.hasChildrenAddress(info.mChildrenAddress)) { + Position childrenPos = new Position(info.mChildrenAddress + headerSize, index); + stack.push(childrenPos); + } + } + } + + /** + * Reads unigrams and bigrams from the binary file. + * Doesn't make the memory representation of the dictionary. + * + * @param buffer the buffer to read. + * @param words the map to store the address as a key and the word as a value. + * @param frequencies the map to store the address as a key and the frequency as a value. + * @param bigrams the map to store the address as a key and the list of address as a value. + * @throws IOException + * @throws UnsupportedFormatException + */ + public static void readUnigramsAndBigramsBinary(final FusionDictionaryBufferInterface buffer, + final Map<Integer, String> words, final Map<Integer, Integer> frequencies, + final Map<Integer, ArrayList<PendingAttribute>> bigrams) throws IOException, + UnsupportedFormatException { + // Read header + final FileHeader header = BinaryDictInputOutput.readHeader(buffer); + readUnigramsAndBigramsBinaryInner(buffer, header.mHeaderSize, words, frequencies, bigrams, + header.mFormatOptions); + } +} diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 72d12299b..c865702d6 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -63,6 +63,7 @@ public class BinaryDictInputOutput { public int position(); public void position(int newPosition); public void put(final byte b); + public int limit(); } public static final class ByteBufferWrapper implements FusionDictionaryBufferInterface { @@ -107,6 +108,11 @@ public class BinaryDictInputOutput { public void put(final byte b) { mBuffer.put(b); } + + @Override + public int limit() { + return mBuffer.limit(); + } } /** @@ -284,7 +290,7 @@ public class BinaryDictInputOutput { * @param count the group count * @return the size of the group count, either 1 or 2 bytes. */ - private static int getGroupCountSize(final int count) { + public static int getGroupCountSize(final int count) { if (FormatSpec.MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= count) { return 1; } else if (FormatSpec.MAX_CHARGROUPS_IN_A_NODE >= count) { @@ -379,7 +385,7 @@ public class BinaryDictInputOutput { /** * Helper method to hide the actual value of the no children address. */ - private static boolean hasChildrenAddress(final int address) { + public static boolean hasChildrenAddress(final int address) { return FormatSpec.NO_CHILDREN_ADDRESS != address; } @@ -1099,7 +1105,7 @@ public class BinaryDictInputOutput { // readDictionaryBinary is the public entry point for them. private static final int[] CHARACTER_BUFFER = new int[FormatSpec.MAX_WORD_LENGTH]; - private static CharGroupInfo readCharGroup(final FusionDictionaryBufferInterface buffer, + public static CharGroupInfo readCharGroup(final FusionDictionaryBufferInterface buffer, final int originalGroupAddress, final FormatOptions options) { int addressPointer = originalGroupAddress; final int flags = buffer.readUnsignedByte(); @@ -1212,7 +1218,7 @@ public class BinaryDictInputOutput { /** * Reads and returns the char group count out of a buffer and forwards the pointer. */ - private static int readCharGroupCount(final FusionDictionaryBufferInterface buffer) { + public static int readCharGroupCount(final FusionDictionaryBufferInterface buffer) { final int msb = buffer.readUnsignedByte(); if (FormatSpec.MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= msb) { return msb; @@ -1341,146 +1347,67 @@ public class BinaryDictInputOutput { final Map<Integer, Node> reverseNodeMap, final Map<Integer, CharGroup> reverseGroupMap, final FormatOptions options) throws IOException { - final int nodeOrigin = buffer.position() - headerSize; - final int count = readCharGroupCount(buffer); final ArrayList<CharGroup> nodeContents = new ArrayList<CharGroup>(); - int groupOffset = nodeOrigin + getGroupCountSize(count); - for (int i = count; i > 0; --i) { - CharGroupInfo info = readCharGroup(buffer, groupOffset, options); - ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets; - ArrayList<WeightedString> bigrams = null; - if (null != info.mBigrams) { - bigrams = new ArrayList<WeightedString>(); - for (PendingAttribute bigram : info.mBigrams) { - final String word = getWordAtAddress( - buffer, headerSize, bigram.mAddress, options); - bigrams.add(new WeightedString(word, bigram.mFrequency)); + final int nodeOrigin = buffer.position() - headerSize; + + do { // Scan the linked-list node. + final int nodeHeadPosition = buffer.position() - headerSize; + final int count = readCharGroupCount(buffer); + int groupOffset = nodeHeadPosition + getGroupCountSize(count); + for (int i = count; i > 0; --i) { // Scan the array of CharGroup. + CharGroupInfo info = readCharGroup(buffer, groupOffset, options); + ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets; + ArrayList<WeightedString> bigrams = null; + if (null != info.mBigrams) { + bigrams = new ArrayList<WeightedString>(); + for (PendingAttribute bigram : info.mBigrams) { + final String word = getWordAtAddress( + buffer, headerSize, bigram.mAddress, options); + bigrams.add(new WeightedString(word, bigram.mFrequency)); + } + } + if (hasChildrenAddress(info.mChildrenAddress)) { + Node children = reverseNodeMap.get(info.mChildrenAddress); + if (null == children) { + final int currentPosition = buffer.position(); + buffer.position(info.mChildrenAddress + headerSize); + children = readNode( + buffer, headerSize, reverseNodeMap, reverseGroupMap, options); + buffer.position(currentPosition); + } + nodeContents.add( + new CharGroup(info.mCharacters, shortcutTargets, bigrams, + info.mFrequency, + 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), + 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED), children)); + } else { + nodeContents.add( + new CharGroup(info.mCharacters, shortcutTargets, bigrams, + info.mFrequency, + 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), + 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED))); } + groupOffset = info.mEndAddress; } - if (hasChildrenAddress(info.mChildrenAddress)) { - Node children = reverseNodeMap.get(info.mChildrenAddress); - if (null == children) { - final int currentPosition = buffer.position(); - buffer.position(info.mChildrenAddress + headerSize); - children = readNode( - buffer, headerSize, reverseNodeMap, reverseGroupMap, options); - buffer.position(currentPosition); + + // reach the end of the array. + if (options.mHasLinkedListNode) { + final int nextAddress = buffer.readUnsignedInt24(); + if (nextAddress >= 0 && nextAddress < buffer.limit()) { + buffer.position(nextAddress); + } else { + break; } - nodeContents.add( - new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency, - 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), - 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED), children)); - } else { - nodeContents.add( - new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency, - 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), - 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED))); } - groupOffset = info.mEndAddress; - } + } while (options.mHasLinkedListNode && + buffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS); + final Node node = new Node(nodeContents); node.mCachedAddress = nodeOrigin; reverseNodeMap.put(node.mCachedAddress, node); return node; } - // TODO: move these methods (readUnigramsAndBigramsBinary(|Inner)) and an inner class (Position) - // out of this class. - private static class Position { - public static final int NOT_READ_GROUPCOUNT = -1; - - public int mAddress; - public int mNumOfCharGroup; - public int mPosition; - public int mLength; - - public Position(int address, int length) { - mAddress = address; - mLength = length; - mNumOfCharGroup = NOT_READ_GROUPCOUNT; - } - } - - /** - * Tours all node without recursive call. - */ - private static void readUnigramsAndBigramsBinaryInner( - final FusionDictionaryBufferInterface buffer, final int headerSize, - final Map<Integer, String> words, final Map<Integer, Integer> frequencies, - final Map<Integer, ArrayList<PendingAttribute>> bigrams, - final FormatOptions formatOptions) { - int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1]; - - Stack<Position> stack = new Stack<Position>(); - int index = 0; - - Position initPos = new Position(headerSize, 0); - stack.push(initPos); - - while (!stack.empty()) { - Position p = stack.peek(); - - if (DBG) { - MakedictLog.d("read: address=" + p.mAddress + ", numOfCharGroup=" + - p.mNumOfCharGroup + ", position=" + p.mPosition + ", length=" + p.mLength); - } - - if (buffer.position() != p.mAddress) buffer.position(p.mAddress); - if (index != p.mLength) index = p.mLength; - - if (p.mNumOfCharGroup == Position.NOT_READ_GROUPCOUNT) { - p.mNumOfCharGroup = readCharGroupCount(buffer); - p.mAddress += getGroupCountSize(p.mNumOfCharGroup); - p.mPosition = 0; - } - - CharGroupInfo info = readCharGroup(buffer, p.mAddress - headerSize, formatOptions); - for (int i = 0; i < info.mCharacters.length; ++i) { - pushedChars[index++] = info.mCharacters[i]; - } - p.mPosition++; - - if (info.mFrequency != FusionDictionary.CharGroup.NOT_A_TERMINAL) { // found word - words.put(info.mOriginalAddress, new String(pushedChars, 0, index)); - frequencies.put(info.mOriginalAddress, info.mFrequency); - if (info.mBigrams != null) bigrams.put(info.mOriginalAddress, info.mBigrams); - } - - if (p.mPosition == p.mNumOfCharGroup) { - stack.pop(); - } else { - // the node has more groups. - p.mAddress = buffer.position(); - } - - if (hasChildrenAddress(info.mChildrenAddress)) { - Position childrenPos = new Position(info.mChildrenAddress + headerSize, index); - stack.push(childrenPos); - } - } - } - - /** - * Reads unigrams and bigrams from the binary file. - * Doesn't make the memory representation of the dictionary. - * - * @param buffer the buffer to read. - * @param words the map to store the address as a key and the word as a value. - * @param frequencies the map to store the address as a key and the frequency as a value. - * @param bigrams the map to store the address as a key and the list of address as a value. - * @throws IOException - * @throws UnsupportedFormatException - */ - public static void readUnigramsAndBigramsBinary(final FusionDictionaryBufferInterface buffer, - final Map<Integer, String> words, final Map<Integer, Integer> frequencies, - final Map<Integer, ArrayList<PendingAttribute>> bigrams) throws IOException, - UnsupportedFormatException { - // Read header - final FileHeader header = readHeader(buffer); - readUnigramsAndBigramsBinaryInner(buffer, header.mHeaderSize, words, frequencies, bigrams, - header.mFormatOptions); - } - /** * Helper function to get the binary format version from the header. * @throws IOException @@ -1517,7 +1444,7 @@ public class BinaryDictInputOutput { * @throws IOException * @throws UnsupportedFormatException */ - private static FileHeader readHeader(final FusionDictionaryBufferInterface buffer) + public static FileHeader readHeader(final FusionDictionaryBufferInterface buffer) throws IOException, UnsupportedFormatException { final int version = checkFormatVersion(buffer); final int optionsFlags = buffer.readUnsignedShort(); |