aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java26
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java166
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java29
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java70
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java79
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java27
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java223
7 files changed, 464 insertions, 156 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 67f37a7e7..b5b3ef65f 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -17,14 +17,13 @@
package com.android.inputmethod.keyboard;
import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
import android.os.SystemClock;
import android.util.Log;
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.PointerTrackerQueue;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.InputPointers;
@@ -211,7 +210,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
private static final KeyboardActionListener EMPTY_LISTENER =
new KeyboardActionListener.Adapter();
- private final GestureStroke mGestureStroke;
+ private final GestureStrokeWithPreviewTrail mGestureStrokeWithPreviewTrail;
public static void init(boolean hasDistinctMultitouch,
boolean needsPhantomSuddenMoveEventHack) {
@@ -297,7 +296,8 @@ 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.mGestureStroke.appendIncrementalBatchPoints(sAggregratedPointers);
+ tracker.mGestureStrokeWithPreviewTrail.appendIncrementalBatchPoints(
+ sAggregratedPointers);
}
return sAggregratedPointers;
}
@@ -308,7 +308,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.mGestureStroke.appendAllBatchPoints(sAggregratedPointers);
+ tracker.mGestureStrokeWithPreviewTrail.appendAllBatchPoints(sAggregratedPointers);
}
return sAggregratedPointers;
}
@@ -319,7 +319,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.mGestureStroke.reset();
+ tracker.mGestureStrokeWithPreviewTrail.reset();
}
sAggregratedPointers.reset();
}
@@ -329,7 +329,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
throw new NullPointerException();
}
mPointerId = id;
- mGestureStroke = new GestureStroke(id);
+ mGestureStrokeWithPreviewTrail = new GestureStrokeWithPreviewTrail(id);
setKeyDetectorInner(handler.getKeyDetector());
mListener = handler.getKeyboardActionListener();
mDrawingProxy = handler.getDrawingProxy();
@@ -429,7 +429,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
mKeyDetector = keyDetector;
mKeyboard = keyDetector.getKeyboard();
mIsAlphabetKeyboard = mKeyboard.mId.isAlphabetKeyboard();
- mGestureStroke.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth);
+ mGestureStrokeWithPreviewTrail.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth);
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
if (newKey != mCurrentKey) {
if (mDrawingProxy != null) {
@@ -539,10 +539,8 @@ public class PointerTracker implements PointerTrackerQueue.Element {
mDrawingProxy.invalidateKey(key);
}
- public void drawGestureTrail(final Canvas canvas, final Paint paint) {
- if (mInGesture) {
- mGestureStroke.drawGestureTrail(canvas, paint);
- }
+ public GestureStrokeWithPreviewTrail getGestureStrokeWithPreviewTrail() {
+ return mGestureStrokeWithPreviewTrail;
}
public int getLastX() {
@@ -692,7 +690,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
mIsPossibleGesture = true;
// TODO: pointer times should be relative to first down even in entire batch input
// instead of resetting to 0 for each new down event.
- mGestureStroke.addPoint(x, y, 0, false);
+ mGestureStrokeWithPreviewTrail.addPoint(x, y, 0, false);
}
}
}
@@ -733,7 +731,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
final long eventTime, final boolean isHistorical, final Key key) {
final int gestureTime = (int)(eventTime - tracker.getDownTime());
if (sShouldHandleGesture && mIsPossibleGesture) {
- final GestureStroke stroke = mGestureStroke;
+ final GestureStroke stroke = mGestureStrokeWithPreviewTrail;
stroke.addPoint(x, y, gestureTime, isHistorical);
if (!mInGesture && stroke.isStartOfAGesture()) {
startBatchInput();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
new file mode 100644
index 000000000..e814d8009
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.SystemClock;
+
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResizableIntArray;
+
+class GesturePreviewTrail {
+ private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewTrail.PREVIEW_CAPACITY;
+
+ private final GesturePreviewTrailParams mPreviewParams;
+ private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
+ private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
+ private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY);
+ private int mCurrentStrokeId = -1;
+ private long mCurrentDownTime;
+ private int mTrailStartIndex;
+
+ // Use this value as imaginary zero because x-coordinates may be zero.
+ private static final int DOWN_EVENT_MARKER = -128;
+
+ static class GesturePreviewTrailParams {
+ public final int mFadeoutStartDelay;
+ public final int mFadeoutDuration;
+ public final int mUpdateInterval;
+
+ public GesturePreviewTrailParams(final TypedArray keyboardViewAttr) {
+ mFadeoutStartDelay = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_gesturePreviewTrailFadeoutStartDelay, 0);
+ mFadeoutDuration = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_gesturePreviewTrailFadeoutDuration, 0);
+ mUpdateInterval = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_gesturePreviewTrailUpdateInterval, 0);
+ }
+ }
+
+ public GesturePreviewTrail(final GesturePreviewTrailParams params) {
+ mPreviewParams = params;
+ }
+
+ private static int markAsDownEvent(final int xCoord) {
+ return DOWN_EVENT_MARKER - xCoord;
+ }
+
+ private static boolean isDownEventXCoord(final int xCoordOrMark) {
+ return xCoordOrMark <= DOWN_EVENT_MARKER;
+ }
+
+ private static int getXCoordValue(final int xCoordOrMark) {
+ return isDownEventXCoord(xCoordOrMark)
+ ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark;
+ }
+
+ public void addStroke(final GestureStrokeWithPreviewTrail stroke, final long downTime) {
+ final int strokeId = stroke.getGestureStrokeId();
+ final boolean isNewStroke = strokeId != mCurrentStrokeId;
+ final int trailSize = mEventTimes.getLength();
+ stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates);
+ final int newTrailSize = mEventTimes.getLength();
+ if (stroke.getGestureStrokePreviewSize() == 0) {
+ return;
+ }
+ if (isNewStroke) {
+ final int elapsedTime = (int)(downTime - mCurrentDownTime);
+ final int[] eventTimes = mEventTimes.getPrimitiveArray();
+ for (int i = mTrailStartIndex; i < trailSize; i++) {
+ eventTimes[i] -= elapsedTime;
+ }
+
+ if (newTrailSize > trailSize) {
+ final int[] xCoords = mXCoordinates.getPrimitiveArray();
+ xCoords[trailSize] = markAsDownEvent(xCoords[trailSize]);
+ }
+ mCurrentDownTime = downTime;
+ mCurrentStrokeId = strokeId;
+ }
+ }
+
+ private int getAlpha(final int elapsedTime) {
+ if (elapsedTime < mPreviewParams.mFadeoutStartDelay) {
+ return Constants.Color.ALPHA_OPAQUE;
+ }
+ final int decreasingAlpha = Constants.Color.ALPHA_OPAQUE
+ * (elapsedTime - mPreviewParams.mFadeoutStartDelay)
+ / mPreviewParams.mFadeoutDuration;
+ return Constants.Color.ALPHA_OPAQUE - decreasingAlpha;
+ }
+
+ /**
+ * Draw gesture preview trail
+ * @param canvas The canvas to draw the gesture preview trail
+ * @param paint The paint object to be used to draw the gesture preview trail
+ * @return true if some gesture preview trails remain to be drawn
+ */
+ public boolean drawGestureTrail(final Canvas canvas, final Paint paint) {
+ final int trailSize = mEventTimes.getLength();
+ if (trailSize == 0) {
+ return false;
+ }
+
+ final int[] eventTimes = mEventTimes.getPrimitiveArray();
+ final int[] xCoords = mXCoordinates.getPrimitiveArray();
+ final int[] yCoords = mYCoordinates.getPrimitiveArray();
+ final int sinceDown = (int)(SystemClock.uptimeMillis() - mCurrentDownTime);
+ final int lingeringDuration = mPreviewParams.mFadeoutStartDelay
+ + mPreviewParams.mFadeoutDuration;
+ int startIndex;
+ for (startIndex = mTrailStartIndex; startIndex < trailSize; startIndex++) {
+ final int elapsedTime = sinceDown - eventTimes[startIndex];
+ // Skip too old trail points.
+ if (elapsedTime < lingeringDuration) {
+ break;
+ }
+ }
+ mTrailStartIndex = startIndex;
+
+ if (startIndex < trailSize) {
+ int lastX = getXCoordValue(xCoords[startIndex]);
+ int lastY = yCoords[startIndex];
+ for (int i = startIndex + 1; i < trailSize - 1; i++) {
+ final int x = xCoords[i];
+ final int y = yCoords[i];
+ final int elapsedTime = sinceDown - eventTimes[i];
+ // Draw trail line only when the current point isn't a down point.
+ if (!isDownEventXCoord(x)) {
+ paint.setAlpha(getAlpha(elapsedTime));
+ canvas.drawLine(lastX, lastY, x, y, paint);
+ }
+ lastX = getXCoordValue(x);
+ lastY = y;
+ }
+ }
+
+ final int newSize = trailSize - startIndex;
+ if (newSize < startIndex) {
+ mTrailStartIndex = 0;
+ if (newSize > 0) {
+ System.arraycopy(eventTimes, startIndex, eventTimes, 0, newSize);
+ System.arraycopy(xCoords, startIndex, xCoords, 0, newSize);
+ System.arraycopy(yCoords, startIndex, yCoords, 0, newSize);
+ }
+ mEventTimes.setLength(newSize);
+ mXCoordinates.setLength(newSize);
+ mYCoordinates.setLength(newSize);
+ }
+ return newSize > 0;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index 79e977a40..292842d22 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -14,10 +14,6 @@
package com.android.inputmethod.keyboard.internal;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-
-import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.ResizableIntArray;
@@ -48,13 +44,8 @@ public class GestureStroke {
private static final float DOUBLE_PI = (float)(2.0f * Math.PI);
- // Fade based on number of gesture samples, see MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT
- private static final int DRAWING_GESTURE_FADE_START = 10;
- private static final int DRAWING_GESTURE_FADE_RATE = 6;
-
- public GestureStroke(int pointerId) {
+ public GestureStroke(final int pointerId) {
mPointerId = pointerId;
- reset();
}
public void setGestureSampleLength(final int keyWidth) {
@@ -158,7 +149,7 @@ public class GestureStroke {
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((double)dy, (double)dx);
+ return (float)Math.atan2(dy, dx);
}
private static float getAngleDiff(final float a1, final float a2) {
@@ -168,20 +159,4 @@ public class GestureStroke {
}
return diff;
}
-
- public void drawGestureTrail(final Canvas canvas, final Paint paint) {
- // TODO: These paint parameter interpolation should be tunable, possibly introduce an object
- // that implements an interface such as Paint getPaint(int step, int strokePoints)
- final int size = mXCoordinates.getLength();
- final int[] xCoords = mXCoordinates.getPrimitiveArray();
- final int[] yCoords = mYCoordinates.getPrimitiveArray();
- int alpha = Constants.Color.ALPHA_OPAQUE;
- for (int i = size - 1; i > 0 && alpha > 0; i--) {
- paint.setAlpha(alpha);
- if (size - i > DRAWING_GESTURE_FADE_START) {
- alpha -= DRAWING_GESTURE_FADE_RATE;
- }
- canvas.drawLine(xCoords[i - 1], yCoords[i - 1], xCoords[i], yCoords[i], paint);
- }
- }
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java
new file mode 100644
index 000000000..6c1a9bc01
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import com.android.inputmethod.latin.ResizableIntArray;
+
+public class GestureStrokeWithPreviewTrail extends GestureStroke {
+ public static final int PREVIEW_CAPACITY = 256;
+
+ private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY);
+ private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
+ private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
+
+ private int mStrokeId;
+ private int mLastPreviewSize;
+
+ public GestureStrokeWithPreviewTrail(final int pointerId) {
+ super(pointerId);
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ mStrokeId++;
+ mLastPreviewSize = 0;
+ mPreviewEventTimes.setLength(0);
+ mPreviewXCoordinates.setLength(0);
+ mPreviewYCoordinates.setLength(0);
+ }
+
+ public int getGestureStrokeId() {
+ return mStrokeId;
+ }
+
+ public int getGestureStrokePreviewSize() {
+ return mPreviewEventTimes.getLength();
+ }
+
+ @Override
+ public void addPoint(final int x, final int y, final int time, final boolean isHistorical) {
+ super.addPoint(x, y, time, isHistorical);
+ mPreviewEventTimes.add(time);
+ mPreviewXCoordinates.add(x);
+ mPreviewYCoordinates.add(y);
+ }
+
+ public void appendPreviewStroke(final ResizableIntArray eventTimes,
+ final ResizableIntArray xCoords, final ResizableIntArray yCoords) {
+ final int length = mPreviewEventTimes.getLength() - mLastPreviewSize;
+ if (length <= 0) {
+ return;
+ }
+ eventTimes.append(mPreviewEventTimes, mLastPreviewSize, length);
+ xCoords.append(mPreviewXCoordinates, mLastPreviewSize, length);
+ yCoords.append(mPreviewYCoordinates, mLastPreviewSize, length);
+ mLastPreviewSize = mPreviewEventTimes.getLength();
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index 3f33aee5a..269b202b5 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -28,6 +28,7 @@ import android.util.SparseArray;
import android.widget.RelativeLayout;
import com.android.inputmethod.keyboard.PointerTracker;
+import com.android.inputmethod.keyboard.internal.GesturePreviewTrail.GesturePreviewTrailParams;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
@@ -48,7 +49,9 @@ public class PreviewPlacerView extends RelativeLayout {
private int mXOrigin;
private int mYOrigin;
- private final SparseArray<PointerTracker> mPointers = CollectionUtils.newSparseArray();
+ private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails =
+ CollectionUtils.newSparseArray();
+ private final GesturePreviewTrailParams mGesturePreviewTrailParams;
private String mGestureFloatingPreviewText;
private int mLastPointerX;
@@ -57,23 +60,31 @@ public class PreviewPlacerView extends RelativeLayout {
private boolean mDrawsGesturePreviewTrail;
private boolean mDrawsGestureFloatingPreviewText;
- private final DrawingHandler mDrawingHandler = new DrawingHandler(this);
+ private final DrawingHandler mDrawingHandler;
private static class DrawingHandler extends StaticInnerHandlerWrapper<PreviewPlacerView> {
private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 0;
+ private static final int MSG_UPDATE_GESTURE_PREVIEW_TRAIL = 1;
- public DrawingHandler(PreviewPlacerView outerInstance) {
+ private final GesturePreviewTrailParams mGesturePreviewTrailParams;
+
+ public DrawingHandler(final PreviewPlacerView outerInstance,
+ final GesturePreviewTrailParams gesturePreviewTrailParams) {
super(outerInstance);
+ mGesturePreviewTrailParams = gesturePreviewTrailParams;
}
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(final Message msg) {
final PreviewPlacerView placerView = getOuterInstance();
if (placerView == null) return;
switch (msg.what) {
case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT:
placerView.setGestureFloatingPreviewText(null);
break;
+ case MSG_UPDATE_GESTURE_PREVIEW_TRAIL:
+ placerView.invalidate();
+ break;
}
}
@@ -89,16 +100,27 @@ public class PreviewPlacerView extends RelativeLayout {
placerView.mGestureFloatingPreviewTextLingerTimeout);
}
+ private void cancelUpdateGestureTrailPreview() {
+ removeMessages(MSG_UPDATE_GESTURE_PREVIEW_TRAIL);
+ }
+
+ public void postUpdateGestureTrailPreview() {
+ cancelUpdateGestureTrailPreview();
+ sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_PREVIEW_TRAIL),
+ mGesturePreviewTrailParams.mUpdateInterval);
+ }
+
public void cancelAllMessages() {
cancelDismissGestureFloatingPreviewText();
+ cancelUpdateGestureTrailPreview();
}
}
- public PreviewPlacerView(Context context, AttributeSet attrs) {
+ public PreviewPlacerView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.keyboardViewStyle);
}
- public PreviewPlacerView(Context context, AttributeSet attrs, int defStyle) {
+ public PreviewPlacerView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context);
setWillNotDraw(false);
@@ -128,8 +150,11 @@ public class PreviewPlacerView extends RelativeLayout {
R.styleable.KeyboardView_gesturePreviewTrailColor, 0);
final int gesturePreviewTrailWidth = keyboardViewAttr.getDimensionPixelSize(
R.styleable.KeyboardView_gesturePreviewTrailWidth, 0);
+ mGesturePreviewTrailParams = new GesturePreviewTrailParams(keyboardViewAttr);
keyboardViewAttr.recycle();
+ mDrawingHandler = new DrawingHandler(this, mGesturePreviewTrailParams);
+
mGesturePaint = new Paint();
mGesturePaint.setAntiAlias(true);
mGesturePaint.setStyle(Paint.Style.STROKE);
@@ -144,21 +169,28 @@ public class PreviewPlacerView extends RelativeLayout {
mTextPaint.setTextSize(gestureFloatingPreviewTextSize);
}
- public void setOrigin(int x, int y) {
+ public void setOrigin(final int x, final int y) {
mXOrigin = x;
mYOrigin = y;
}
- public void setGesturePreviewMode(boolean drawsGesturePreviewTrail,
- boolean drawsGestureFloatingPreviewText) {
+ public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail,
+ final boolean drawsGestureFloatingPreviewText) {
mDrawsGesturePreviewTrail = drawsGesturePreviewTrail;
mDrawsGestureFloatingPreviewText = drawsGestureFloatingPreviewText;
}
- public void invalidatePointer(PointerTracker tracker) {
- synchronized (mPointers) {
- mPointers.put(tracker.mPointerId, tracker);
+ public void invalidatePointer(final PointerTracker tracker) {
+ GesturePreviewTrail trail;
+ synchronized (mGesturePreviewTrails) {
+ trail = mGesturePreviewTrails.get(tracker.mPointerId);
+ if (trail == null) {
+ trail = new GesturePreviewTrail(mGesturePreviewTrailParams);
+ mGesturePreviewTrails.put(tracker.mPointerId, trail);
+ }
}
+ trail.addStroke(tracker.getGestureStrokeWithPreviewTrail(), tracker.getDownTime());
+
mLastPointerX = tracker.getLastX();
mLastPointerY = tracker.getLastY();
// TODO: Should narrow the invalidate region.
@@ -166,17 +198,23 @@ public class PreviewPlacerView extends RelativeLayout {
}
@Override
- public void onDraw(Canvas canvas) {
+ public void onDraw(final Canvas canvas) {
super.onDraw(canvas);
canvas.translate(mXOrigin, mYOrigin);
if (mDrawsGesturePreviewTrail) {
- synchronized (mPointers) {
- final int trackerCount = mPointers.size();
- for (int index = 0; index < trackerCount; index++) {
- final PointerTracker tracker = mPointers.valueAt(index);
- tracker.drawGestureTrail(canvas, mGesturePaint);
+ boolean needsUpdatingGesturePreviewTrail = false;
+ synchronized (mGesturePreviewTrails) {
+ // Trails count == fingers count that have ever been active.
+ final int trailsCount = mGesturePreviewTrails.size();
+ for (int index = 0; index < trailsCount; index++) {
+ final GesturePreviewTrail trail = mGesturePreviewTrails.valueAt(index);
+ needsUpdatingGesturePreviewTrail |=
+ trail.drawGestureTrail(canvas, mGesturePaint);
}
}
+ if (needsUpdatingGesturePreviewTrail) {
+ mDrawingHandler.postUpdateGestureTrailPreview();
+ }
}
if (mDrawsGestureFloatingPreviewText) {
drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
@@ -184,7 +222,7 @@ public class PreviewPlacerView extends RelativeLayout {
canvas.translate(-mXOrigin, -mYOrigin);
}
- public void setGestureFloatingPreviewText(String gestureFloatingPreviewText) {
+ public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) {
mGestureFloatingPreviewText = gestureFloatingPreviewText;
invalidate();
}
@@ -197,7 +235,8 @@ public class PreviewPlacerView extends RelativeLayout {
mDrawingHandler.cancelAllMessages();
}
- private void drawGestureFloatingPreviewText(Canvas canvas, String gestureFloatingPreviewText) {
+ private void drawGestureFloatingPreviewText(final Canvas canvas,
+ final String gestureFloatingPreviewText) {
if (TextUtils.isEmpty(gestureFloatingPreviewText)) {
return;
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 4ada909de..e1cb195bc 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -25,7 +25,10 @@ import android.content.res.AssetFileDescriptor;
import android.util.Log;
import java.io.File;
-import java.io.RandomAccessFile;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
@@ -349,17 +352,21 @@ class BinaryDictionaryGetter {
// ad-hock ## HACK ##
if (!Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) return true;
+ FileInputStream inStream = null;
try {
// Read the version of the file
- final RandomAccessFile raf = new RandomAccessFile(f, "r");
- final int magic = raf.readInt();
+ inStream = new FileInputStream(f);
+ final ByteBuffer buffer = inStream.getChannel().map(
+ FileChannel.MapMode.READ_ONLY, 0, f.length());
+ final int magic = buffer.getInt();
if (magic != BinaryDictInputOutput.VERSION_2_MAGIC_NUMBER) {
return false;
}
- final int formatVersion = raf.readInt();
- final int headerSize = raf.readInt();
+ final int formatVersion = buffer.getInt();
+ final int headerSize = buffer.getInt();
final HashMap<String, String> options = CollectionUtils.newHashMap();
- BinaryDictInputOutput.populateOptionsFromFile(raf, headerSize, options);
+ BinaryDictInputOutput.populateOptions(buffer, headerSize, options);
+
final String version = options.get(VERSION_KEY);
if (null == version) {
// No version in the options : the format is unexpected
@@ -374,6 +381,14 @@ class BinaryDictionaryGetter {
return false;
} catch (NumberFormatException e) {
return false;
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index b23b7db34..161b94ca0 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -22,10 +22,13 @@ import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
-import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -307,33 +310,32 @@ public class BinaryDictInputOutput {
}
/**
- * Reads a string from a RandomAccessFile. This is the converse of the above method.
+ * Reads a string from a ByteBuffer. This is the converse of the above method.
*/
- private static String readString(final RandomAccessFile source) throws IOException {
+ private static String readString(final ByteBuffer buffer) {
final StringBuilder s = new StringBuilder();
- int character = readChar(source);
+ int character = readChar(buffer);
while (character != INVALID_CHARACTER) {
s.appendCodePoint(character);
- character = readChar(source);
+ character = readChar(buffer);
}
return s.toString();
}
/**
- * Reads a character from the file.
+ * Reads a character from the ByteBuffer.
*
* This follows the character format documented earlier in this source file.
*
- * @param source the file, positioned over an encoded character.
+ * @param buffer the buffer, positioned over an encoded character.
* @return the character code.
*/
- private static int readChar(RandomAccessFile source) throws IOException {
- int character = source.readUnsignedByte();
+ private static int readChar(final ByteBuffer buffer) {
+ int character = readUnsignedByte(buffer);
if (!fitsOnOneByte(character)) {
- if (GROUP_CHARACTERS_TERMINATOR == character)
- return INVALID_CHARACTER;
+ if (GROUP_CHARACTERS_TERMINATOR == character) return INVALID_CHARACTER;
character <<= 16;
- character += source.readUnsignedShort();
+ character += readUnsignedShort(buffer);
}
return character;
}
@@ -1091,46 +1093,46 @@ public class BinaryDictInputOutput {
// readDictionaryBinary is the public entry point for them.
static final int[] characterBuffer = new int[MAX_WORD_LENGTH];
- private static CharGroupInfo readCharGroup(RandomAccessFile source,
- final int originalGroupAddress) throws IOException {
+ private static CharGroupInfo readCharGroup(final ByteBuffer buffer,
+ final int originalGroupAddress) {
int addressPointer = originalGroupAddress;
- final int flags = source.readUnsignedByte();
+ final int flags = readUnsignedByte(buffer);
++addressPointer;
final int characters[];
if (0 != (flags & FLAG_HAS_MULTIPLE_CHARS)) {
int index = 0;
- int character = CharEncoding.readChar(source);
+ int character = CharEncoding.readChar(buffer);
addressPointer += CharEncoding.getCharSize(character);
while (-1 != character) {
characterBuffer[index++] = character;
- character = CharEncoding.readChar(source);
+ character = CharEncoding.readChar(buffer);
addressPointer += CharEncoding.getCharSize(character);
}
characters = Arrays.copyOfRange(characterBuffer, 0, index);
} else {
- final int character = CharEncoding.readChar(source);
+ final int character = CharEncoding.readChar(buffer);
addressPointer += CharEncoding.getCharSize(character);
characters = new int[] { character };
}
final int frequency;
if (0 != (FLAG_IS_TERMINAL & flags)) {
++addressPointer;
- frequency = source.readUnsignedByte();
+ frequency = readUnsignedByte(buffer);
} else {
frequency = CharGroup.NOT_A_TERMINAL;
}
int childrenAddress = addressPointer;
switch (flags & MASK_GROUP_ADDRESS_TYPE) {
case FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
- childrenAddress += source.readUnsignedByte();
+ childrenAddress += readUnsignedByte(buffer);
addressPointer += 1;
break;
case FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
- childrenAddress += source.readUnsignedShort();
+ childrenAddress += readUnsignedShort(buffer);
addressPointer += 2;
break;
case FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
- childrenAddress += (source.readUnsignedByte() << 16) + source.readUnsignedShort();
+ childrenAddress += readUnsignedInt24(buffer);
addressPointer += 3;
break;
case FLAG_GROUP_ADDRESS_TYPE_NOADDRESS:
@@ -1140,38 +1142,38 @@ public class BinaryDictInputOutput {
}
ArrayList<WeightedString> shortcutTargets = null;
if (0 != (flags & FLAG_HAS_SHORTCUT_TARGETS)) {
- final long pointerBefore = source.getFilePointer();
+ final int pointerBefore = buffer.position();
shortcutTargets = new ArrayList<WeightedString>();
- source.readUnsignedShort(); // Skip the size
+ buffer.getShort(); // Skip the size
while (true) {
- final int targetFlags = source.readUnsignedByte();
- final String word = CharEncoding.readString(source);
+ final int targetFlags = readUnsignedByte(buffer);
+ final String word = CharEncoding.readString(buffer);
shortcutTargets.add(new WeightedString(word,
targetFlags & FLAG_ATTRIBUTE_FREQUENCY));
if (0 == (targetFlags & FLAG_ATTRIBUTE_HAS_NEXT)) break;
}
- addressPointer += (source.getFilePointer() - pointerBefore);
+ addressPointer += buffer.position() - pointerBefore;
}
ArrayList<PendingAttribute> bigrams = null;
if (0 != (flags & FLAG_HAS_BIGRAMS)) {
bigrams = new ArrayList<PendingAttribute>();
while (true) {
- final int bigramFlags = source.readUnsignedByte();
+ final int bigramFlags = readUnsignedByte(buffer);
++addressPointer;
final int sign = 0 == (bigramFlags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) ? 1 : -1;
int bigramAddress = addressPointer;
switch (bigramFlags & MASK_ATTRIBUTE_ADDRESS_TYPE) {
case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
- bigramAddress += sign * source.readUnsignedByte();
+ bigramAddress += sign * readUnsignedByte(buffer);
addressPointer += 1;
break;
case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
- bigramAddress += sign * source.readUnsignedShort();
+ bigramAddress += sign * readUnsignedShort(buffer);
addressPointer += 2;
break;
case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
- final int offset = ((source.readUnsignedByte() << 16)
- + source.readUnsignedShort());
+ final int offset = (readUnsignedByte(buffer) << 16)
+ + readUnsignedShort(buffer);
bigramAddress += sign * offset;
addressPointer += 3;
break;
@@ -1188,15 +1190,15 @@ public class BinaryDictInputOutput {
}
/**
- * Reads and returns the char group count out of a file and forwards the pointer.
+ * Reads and returns the char group count out of a buffer and forwards the pointer.
*/
- private static int readCharGroupCount(RandomAccessFile source) throws IOException {
- final int msb = source.readUnsignedByte();
+ private static int readCharGroupCount(final ByteBuffer buffer) {
+ final int msb = readUnsignedByte(buffer);
if (MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= msb) {
return msb;
} else {
return ((MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT & msb) << 8)
- + source.readUnsignedByte();
+ + readUnsignedByte(buffer);
}
}
@@ -1204,31 +1206,29 @@ public class BinaryDictInputOutput {
// of this method. Since it performs direct, unbuffered random access to the file and
// may be called hundreds of thousands of times, the resulting performance is not
// reasonable without some kind of cache. Thus:
- // TODO: perform buffered I/O here and in other places in the code.
private static TreeMap<Integer, String> wordCache = new TreeMap<Integer, String>();
/**
* Finds, as a string, the word at the address passed as an argument.
*
- * @param source the file to read from.
+ * @param buffer the buffer to read from.
* @param headerSize the size of the header.
* @param address the address to seek.
* @return the word, as a string.
- * @throws IOException if the file can't be read.
*/
- private static String getWordAtAddress(final RandomAccessFile source, final long headerSize,
- int address) throws IOException {
+ private static String getWordAtAddress(final ByteBuffer buffer, final int headerSize,
+ final int address) {
final String cachedString = wordCache.get(address);
if (null != cachedString) return cachedString;
- final long originalPointer = source.getFilePointer();
- source.seek(headerSize);
- final int count = readCharGroupCount(source);
+ final int originalPointer = buffer.position();
+ buffer.position(headerSize);
+ final int count = readCharGroupCount(buffer);
int groupOffset = getGroupCountSize(count);
final StringBuilder builder = new StringBuilder();
String result = null;
CharGroupInfo last = null;
for (int i = count - 1; i >= 0; --i) {
- CharGroupInfo info = readCharGroup(source, groupOffset);
+ CharGroupInfo info = readCharGroup(buffer, groupOffset);
groupOffset = info.mEndAddress;
if (info.mOriginalAddress == address) {
builder.append(new String(info.mCharacters, 0, info.mCharacters.length));
@@ -1239,9 +1239,9 @@ public class BinaryDictInputOutput {
if (info.mChildrenAddress > address) {
if (null == last) continue;
builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
- source.seek(last.mChildrenAddress + headerSize);
+ buffer.position(last.mChildrenAddress + headerSize);
groupOffset = last.mChildrenAddress + 1;
- i = source.readUnsignedByte();
+ i = readUnsignedByte(buffer);
last = null;
continue;
}
@@ -1249,14 +1249,14 @@ public class BinaryDictInputOutput {
}
if (0 == i && hasChildrenAddress(last.mChildrenAddress)) {
builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
- source.seek(last.mChildrenAddress + headerSize);
+ buffer.position(last.mChildrenAddress + headerSize);
groupOffset = last.mChildrenAddress + 1;
- i = source.readUnsignedByte();
+ i = readUnsignedByte(buffer);
last = null;
continue;
}
}
- source.seek(originalPointer);
+ buffer.position(originalPointer);
wordCache.put(address, result);
return result;
}
@@ -1269,44 +1269,47 @@ public class BinaryDictInputOutput {
* This will recursively read other nodes into the structure, populating the reverse
* maps on the fly and using them to keep track of already read nodes.
*
- * @param source the data file, correctly positioned at the start of a node.
+ * @param buffer the buffer, correctly positioned at the start of a node.
* @param headerSize the size, in bytes, of the file header.
* @param reverseNodeMap a mapping from addresses to already read nodes.
* @param reverseGroupMap a mapping from addresses to already read character groups.
* @return the read node with all his children already read.
*/
- private static Node readNode(RandomAccessFile source, long headerSize,
- Map<Integer, Node> reverseNodeMap, Map<Integer, CharGroup> reverseGroupMap)
+ private static Node readNode(final ByteBuffer buffer, final int headerSize,
+ final Map<Integer, Node> reverseNodeMap, final Map<Integer, CharGroup> reverseGroupMap)
throws IOException {
- final int nodeOrigin = (int)(source.getFilePointer() - headerSize);
- final int count = readCharGroupCount(source);
+ 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(source, groupOffset);
+ CharGroupInfo info =readCharGroup(buffer, groupOffset);
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(source, headerSize, bigram.mAddress);
+ final String word = getWordAtAddress(
+ buffer, headerSize, bigram.mAddress);
bigrams.add(new WeightedString(word, bigram.mFrequency));
}
}
if (hasChildrenAddress(info.mChildrenAddress)) {
Node children = reverseNodeMap.get(info.mChildrenAddress);
if (null == children) {
- final long currentPosition = source.getFilePointer();
- source.seek(info.mChildrenAddress + headerSize);
- children = readNode(source, headerSize, reverseNodeMap, reverseGroupMap);
- source.seek(currentPosition);
+ final int currentPosition = buffer.position();
+ buffer.position(info.mChildrenAddress + headerSize);
+ children = readNode(
+ buffer, headerSize, reverseNodeMap, reverseGroupMap);
+ buffer.position(currentPosition);
}
nodeContents.add(
- new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency,
- children));
+ new CharGroup(info.mCharacters, shortcutTargets,
+ bigrams, info.mFrequency, children));
} else {
nodeContents.add(
- new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency));
+ new CharGroup(info.mCharacters, shortcutTargets,
+ bigrams, info.mFrequency));
}
groupOffset = info.mEndAddress;
}
@@ -1318,12 +1321,13 @@ public class BinaryDictInputOutput {
/**
* Helper function to get the binary format version from the header.
+ * @throws IOException
*/
- private static int getFormatVersion(final RandomAccessFile source) throws IOException {
- final int magic_v1 = source.readUnsignedShort();
- if (VERSION_1_MAGIC_NUMBER == magic_v1) return source.readUnsignedByte();
- final int magic_v2 = (magic_v1 << 16) + source.readUnsignedShort();
- if (VERSION_2_MAGIC_NUMBER == magic_v2) return source.readUnsignedShort();
+ private static int getFormatVersion(final ByteBuffer buffer) throws IOException {
+ final int magic_v1 = readUnsignedShort(buffer);
+ if (VERSION_1_MAGIC_NUMBER == magic_v1) return readUnsignedByte(buffer);
+ final int magic_v2 = (magic_v1 << 16) + readUnsignedShort(buffer);
+ if (VERSION_2_MAGIC_NUMBER == magic_v2) return readUnsignedShort(buffer);
return NOT_A_VERSION_NUMBER;
}
@@ -1333,53 +1337,60 @@ public class BinaryDictInputOutput {
* The file is read at the current file pointer, so the caller must take care the pointer
* is in the right place before calling this.
*/
- public static void populateOptionsFromFile(final RandomAccessFile source, final long headerSize,
- final HashMap<String, String> options) throws IOException {
- while (source.getFilePointer() < headerSize) {
- final String key = CharEncoding.readString(source);
- final String value = CharEncoding.readString(source);
+ public static void populateOptions(final ByteBuffer buffer, final int headerSize,
+ final HashMap<String, String> options) {
+ while (buffer.position() < headerSize) {
+ final String key = CharEncoding.readString(buffer);
+ final String value = CharEncoding.readString(buffer);
options.put(key, value);
}
}
/**
- * Reads a random access file and returns the memory representation of the dictionary.
+ * Reads a byte buffer and returns the memory representation of the dictionary.
*
* This high-level method takes a binary file and reads its contents, populating a
* FusionDictionary structure. The optional dict argument is an existing dictionary to
* which words from the file should be added. If it is null, a new dictionary is created.
*
- * @param source the file to read.
+ * @param buffer the buffer to read.
* @param dict an optional dictionary to add words to, or null.
* @return the created (or merged) dictionary.
*/
- public static FusionDictionary readDictionaryBinary(final RandomAccessFile source,
+ public static FusionDictionary readDictionaryBinary(final ByteBuffer buffer,
final FusionDictionary dict) throws IOException, UnsupportedFormatException {
// Check file version
- final int version = getFormatVersion(source);
- if (version < MINIMUM_SUPPORTED_VERSION || version > MAXIMUM_SUPPORTED_VERSION ) {
+ final int version = getFormatVersion(buffer);
+ if (version < MINIMUM_SUPPORTED_VERSION || version > MAXIMUM_SUPPORTED_VERSION) {
throw new UnsupportedFormatException("This file has version " + version
+ ", but this implementation does not support versions above "
+ MAXIMUM_SUPPORTED_VERSION);
}
+ // clear cache
+ wordCache.clear();
+
// Read options
- final int optionsFlags = source.readUnsignedShort();
+ final int optionsFlags = readUnsignedShort(buffer);
- final long headerSize;
+ final int headerSize;
final HashMap<String, String> options = new HashMap<String, String>();
if (version < FIRST_VERSION_WITH_HEADER_SIZE) {
- headerSize = source.getFilePointer();
+ headerSize = buffer.position();
} else {
- headerSize = (source.readUnsignedByte() << 24) + (source.readUnsignedByte() << 16)
- + (source.readUnsignedByte() << 8) + source.readUnsignedByte();
- populateOptionsFromFile(source, headerSize, options);
- source.seek(headerSize);
+ headerSize = buffer.getInt();
+ populateOptions(buffer, headerSize, options);
+ buffer.position(headerSize);
+ }
+
+ if (headerSize < 0) {
+ throw new UnsupportedFormatException("header size can't be negative.");
}
Map<Integer, Node> reverseNodeMapping = new TreeMap<Integer, Node>();
Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
- final Node root = readNode(source, headerSize, reverseNodeMapping, reverseGroupMapping);
+ final Node root = readNode(
+ buffer, headerSize, reverseNodeMapping, reverseGroupMapping);
FusionDictionary newDict = new FusionDictionary(root,
new FusionDictionary.DictionaryOptions(options,
@@ -1403,6 +1414,28 @@ public class BinaryDictInputOutput {
}
/**
+ * Helper function to read one byte from ByteBuffer.
+ */
+ private static int readUnsignedByte(final ByteBuffer buffer) {
+ return ((int)buffer.get()) & 0xFF;
+ }
+
+ /**
+ * Helper function to read two byte from ByteBuffer.
+ */
+ private static int readUnsignedShort(final ByteBuffer buffer) {
+ return ((int)buffer.getShort()) & 0xFFFF;
+ }
+
+ /**
+ * Helper function to read three byte from ByteBuffer.
+ */
+ private static int readUnsignedInt24(final ByteBuffer buffer) {
+ final int value = readUnsignedByte(buffer) << 16;
+ return value + readUnsignedShort(buffer);
+ }
+
+ /**
* Basic test to find out whether the file is a binary dictionary or not.
*
* Concretely this only tests the magic number.
@@ -1411,14 +1444,26 @@ public class BinaryDictInputOutput {
* @return true if it's a binary dictionary, false otherwise
*/
public static boolean isBinaryDictionary(final String filename) {
+ FileInputStream inStream = null;
try {
- RandomAccessFile f = new RandomAccessFile(filename, "r");
- final int version = getFormatVersion(f);
+ final File file = new File(filename);
+ inStream = new FileInputStream(file);
+ final ByteBuffer buffer = inStream.getChannel().map(
+ FileChannel.MapMode.READ_ONLY, 0, file.length());
+ final int version = getFormatVersion(buffer);
return (version >= MINIMUM_SUPPORTED_VERSION && version <= MAXIMUM_SUPPORTED_VERSION);
} catch (FileNotFoundException e) {
return false;
} catch (IOException e) {
return false;
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
}
}