diff options
Diffstat (limited to 'java')
14 files changed, 155 insertions, 671 deletions
diff --git a/java/res/values-en/whitelist.xml b/java/res/values-en/whitelist.xml deleted file mode 100644 index 262017916..000000000 --- a/java/res/values-en/whitelist.xml +++ /dev/null @@ -1,411 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2011, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- - An entry of the whitelist word should be: - 1. (int)frequency - 2. (String)before - 3. (String)after - --> - <string-array name="wordlist_whitelist" translatable="false"> - - <item>255</item> - <item>ill</item> - <item>I\'ll</item> - - <!-- TODO: Trim down more entries by removing ones that get auto-corrected by the - Android keyboard's own typing error correction algorithms. --> - - <item>255</item> - <item>acomodate</item> - <item>accommodate</item> - - <item>255</item> - <item>aint</item> - <item>ain\'t</item> - - <item>255</item> - <item>alot</item> - <item>a lot</item> - - <item>255</item> - <item>andteh</item> - <item>and the</item> - - <item>255</item> - <item>arent</item> - <item>aren\'t</item> - - <item>255</item> - <item>bot</item> - <item>not</item> - - <item>255</item> - <item>bern</item> - <item>been</item> - - <item>255</item> - <item>bot</item> - <item>not</item> - - <item>255</item> - <item>bur</item> - <item>but</item> - - <item>255</item> - <item>cam</item> - <item>can</item> - - <item>255</item> - <item>cant</item> - <item>can\'t</item> - - <item>255</item> - <item>dame</item> - <item>same</item> - - <item>255</item> - <item>didint</item> - <item>didn\'t</item> - - <item>255</item> - <item>dormer</item> - <item>former</item> - - <item>255</item> - <item>dud</item> - <item>did</item> - - <item>255</item> - <item>fay</item> - <item>day</item> - - <item>255</item> - <item>fife</item> - <item>five</item> - - <item>255</item> - <item>foo</item> - <item>for</item> - - <item>255</item> - <item>fora</item> - <item>for a</item> - - <item>255</item> - <item>galled</item> - <item>called</item> - - <item>255</item> - <item>goo</item> - <item>too</item> - - <item>255</item> - <item>hed</item> - <item>he\'d</item> - - <item>255</item> - <item>hel</item> - <item>he\'ll</item> - - <item>255</item> - <item>heres</item> - <item>here\'s</item> - - <item>255</item> - <item>hew</item> - <item>new</item> - - <item>255</item> - <item>hoe</item> - <item>how</item> - - <item>255</item> - <item>hoes</item> - <item>how\'s</item> - - <item>255</item> - <item>howd</item> - <item>how\'d</item> - - <item>255</item> - <item>howll</item> - <item>how\'ll</item> - - <item>255</item> - <item>hows</item> - <item>how\'s</item> - - <item>255</item> - <item>howve</item> - <item>how\'ve</item> - - <item>255</item> - <item>hum</item> - <item>him</item> - - <item>255</item> - <item>i</item> - <item>I</item> - - <item>255</item> - <item>ifs</item> - <item>its</item> - - <item>255</item> - <item>il</item> - <item>I\'ll</item> - - <item>255</item> - <item>im</item> - <item>I\'m</item> - - <item>255</item> - <item>inteh</item> - <item>in the</item> - - <item>255</item> - <item>itd</item> - <item>it\'d</item> - - <item>255</item> - <item>itsa</item> - <item>it\'s a</item> - - <item>255</item> - <item>lets</item> - <item>let\'s</item> - - <item>255</item> - <item>maam</item> - <item>ma\'am</item> - - <item>255</item> - <item>manu</item> - <item>many</item> - - <item>255</item> - <item>mare</item> - <item>made</item> - - <item>255</item> - <item>mew</item> - <item>new</item> - - <item>255</item> - <item>mire</item> - <item>more</item> - - <item>255</item> - <item>moat</item> - <item>most</item> - - <item>255</item> - <item>mot</item> - <item>not</item> - - <item>255</item> - <item>mote</item> - <item>note</item> - - <item>255</item> - <item>motes</item> - <item>notes</item> - - <item>255</item> - <item>mow</item> - <item>now</item> - - <item>255</item> - <item>namer</item> - <item>named</item> - - <item>255</item> - <item>nave</item> - <item>have</item> - - <item>255</item> - <item>nee</item> - <item>new</item> - - <item>255</item> - <item>nigh</item> - <item>high</item> - - <item>255</item> - <item>nit</item> - <item>not</item> - - <item>255</item> - <item>oft</item> - <item>off</item> - - <item>255</item> - <item>os</item> - <item>is</item> - - <item>255</item> - <item>pater</item> - <item>later</item> - - <item>255</item> - <item>rook</item> - <item>took</item> - - <item>255</item> - <item>shel</item> - <item>she\'ll</item> - - <item>255</item> - <item>shouldent</item> - <item>shouldn\'t</item> - - <item>255</item> - <item>sill</item> - <item>will</item> - - <item>255</item> - <item>sown</item> - <item>down</item> - - <item>255</item> - <item>thatd</item> - <item>that\'d</item> - - <item>255</item> - <item>tine</item> - <item>time</item> - - <item>255</item> - <item>thong</item> - <item>thing</item> - - <item>255</item> - <item>tome</item> - <item>time</item> - - <!-- through additional proximity, 'uf' becomes 'of'. 'o' is not next to 'u' so anyone - typing 'uf' probably meant 'if', but 'of' is much more common and should be left - higher than 'if', hence the need for this entry. --> - <item>255</item> - <item>uf</item> - <item>if</item> - - <!-- 'un' becomes 'UN' because of perfect match ; even if we remove 'UN', then 'un' - will become 'on' for the same reason as above. So list this here. --> - <item>255</item> - <item>un</item> - <item>in</item> - - <!-- does it really make any sense to have the following here? --> - <item>255</item> - <item>UnitedStates</item> - <item>United States</item> - - <item>255</item> - <item>unitedstates</item> - <item>United States</item> - - <item>255</item> - <item>visavis</item> - <item>vis-a-vis</item> - - <item>255</item> - <item>wierd</item> - <item>weird</item> - - <item>255</item> - <item>wel</item> - <item>we\'ll</item> - - <item>255</item> - <item>wer</item> - <item>we\'re</item> - - <item>255</item> - <item>whatd</item> - <item>what\'d</item> - - <item>255</item> - <item>whatm</item> - <item>what\'m</item> - - <item>255</item> - <item>whatre</item> - <item>what\'re</item> - - <item>255</item> - <item>whats</item> - <item>what\'s</item> - - <item>255</item> - <item>whens</item> - <item>when\'s</item> - - <item>255</item> - <item>whered</item> - <item>where\'d</item> - - <item>255</item> - <item>wherell</item> - <item>where\'ll</item> - - <item>255</item> - <item>wheres</item> - <item>where\'s</item> - - <item>255</item> - <item>wholl</item> - <item>who\'ll</item> - - <item>255</item> - <item>whove</item> - <item>who\'ve</item> - - <item>255</item> - <item>whyd</item> - <item>why\'d</item> - - <item>255</item> - <item>whyll</item> - <item>why\'ll</item> - - <item>255</item> - <item>whys</item> - <item>why\'s</item> - - <item>255</item> - <item>whyve</item> - <item>why\'ve</item> - - <item>255</item> - <item>wont</item> - <item>won\'t</item> - - <item>255</item> - <item>yall</item> - <item>y\'all</item> - - <item>255</item> - <item>youd</item> - <item>you\'d</item> - - </string-array> -</resources> diff --git a/java/res/values/whitelist.xml b/java/res/values/whitelist.xml deleted file mode 100644 index d4ecbfaa4..000000000 --- a/java/res/values/whitelist.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2011, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- - An entry of the whitelist word should be: - 1. (int)frequency - 2. (String)before - 3. (String)after - --> - <string-array name="wordlist_whitelist"> - </string-array> -</resources> diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 919850095..489cc37ea 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -283,9 +283,10 @@ public class Keyboard { public void load(String[] data) { final int dataLength = data.length; if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) { - if (LatinImeLogger.sDBG) + if (LatinImeLogger.sDBG) { throw new RuntimeException( "the size of touch position correction data is invalid"); + } return; } @@ -324,7 +325,7 @@ public class Keyboard { public boolean isValid() { return mEnabled && mXs != null && mYs != null && mRadii != null - && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0; + && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0; } } @@ -870,10 +871,12 @@ public class Keyboard { final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard); try { - if (a.hasValue(R.styleable.Keyboard_horizontalGap)) + if (a.hasValue(R.styleable.Keyboard_horizontalGap)) { throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap"); - if (a.hasValue(R.styleable.Keyboard_verticalGap)) + } + if (a.hasValue(R.styleable.Keyboard_verticalGap)) { throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap"); + } return new Row(mResources, mParams, parser, mCurrentY); } finally { a.recycle(); @@ -921,7 +924,9 @@ public class Keyboard { throws XmlPullParserException, IOException { if (skip) { XmlParseUtils.checkEndTag(TAG_KEY, parser); - if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY); + if (DEBUG) { + startEndTag("<%s /> skipped", TAG_KEY); + } } else { final Key key = new Key(mResources, mParams, row, parser); if (DEBUG) { @@ -1099,9 +1104,9 @@ public class Keyboard { private boolean parseCaseCondition(XmlPullParser parser) { final KeyboardId id = mParams.mId; - if (id == null) + if (id == null) { return true; - + } final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Case); try { @@ -1205,9 +1210,9 @@ public class Keyboard { // If <case> does not have "index" attribute, that means this <case> is wild-card for // the attribute. final TypedValue v = a.peekValue(index); - if (v == null) + if (v == null) { return true; - + } if (isIntegerValue(v)) { return intValue == a.getInt(index, 0); } else if (isStringValue(v)) { @@ -1218,8 +1223,9 @@ public class Keyboard { private static boolean stringArrayContains(String[] array, String value) { for (final String elem : array) { - if (elem.equals(value)) + if (elem.equals(value)) { return true; + } } return false; } @@ -1242,16 +1248,18 @@ public class Keyboard { TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Key); try { - if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) + if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) { throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE + "/> needs styleName attribute", parser); + } if (DEBUG) { startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE, - keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName), - skip ? " skipped" : ""); + keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName), + skip ? " skipped" : ""); } - if (!skip) + if (!skip) { mParams.mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); + } } finally { keyStyleAttr.recycle(); keyAttrs.recycle(); @@ -1272,8 +1280,9 @@ public class Keyboard { } private void endRow(Row row) { - if (mCurrentRow == null) + if (mCurrentRow == null) { throw new InflateException("orphan end row tag"); + } if (mRightEdgeKey != null) { mRightEdgeKey.markAsRightEdge(mParams); mRightEdgeKey = null; @@ -1309,8 +1318,9 @@ public class Keyboard { public static float getDimensionOrFraction(TypedArray a, int index, int base, float defValue) { final TypedValue value = a.peekValue(index); - if (value == null) + if (value == null) { return defValue; + } if (isFractionValue(value)) { return a.getFraction(index, base, base, defValue); } else if (isDimensionValue(value)) { @@ -1321,8 +1331,9 @@ public class Keyboard { public static int getEnumValue(TypedArray a, int index, int defValue) { final TypedValue value = a.peekValue(index); - if (value == null) + if (value == null) { return defValue; + } if (isIntegerValue(value)) { return a.getInt(index, defValue); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index fcf97b99c..ccbb081b4 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -362,9 +362,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - mKeyDrawParams = new KeyDrawParams(a); mKeyPreviewDrawParams = new KeyPreviewDrawParams(a, mKeyDrawParams); + mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mKeyPreviewLayoutId = a.getResourceId(R.styleable.KeyboardView_keyPreviewLayout, 0); if (mKeyPreviewLayoutId == 0) { mShowKeyPreviewPopup = false; @@ -373,11 +373,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { R.styleable.KeyboardView_verticalCorrection, 0); mMoreKeysLayout = a.getResourceId(R.styleable.KeyboardView_moreKeysLayout, 0); mBackgroundDimAlpha = a.getInt(R.styleable.KeyboardView_backgroundDimAlpha, 0); - mPreviewPlacerView = new PreviewPlacerView(context, a); a.recycle(); - mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; - + mPreviewPlacerView = new PreviewPlacerView(context, attrs); mPaint.setAntiAlias(true); } @@ -462,12 +460,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (bufferNeedsUpdates || mOffscreenBuffer == null) { if (maybeAllocateOffscreenBuffer()) { mInvalidateAllKeys = true; - // TODO: Stop using the offscreen canvas even when in software rendering - if (mOffscreenCanvas != null) { - mOffscreenCanvas.setBitmap(mOffscreenBuffer); - } else { - mOffscreenCanvas = new Canvas(mOffscreenBuffer); - } + maybeCreateOffscreenCanvas(); } onDrawKeyboard(mOffscreenCanvas); } @@ -496,6 +489,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } } + private void maybeCreateOffscreenCanvas() { + // TODO: Stop using the offscreen canvas even when in software rendering + if (mOffscreenCanvas != null) { + mOffscreenCanvas.setBitmap(mOffscreenBuffer); + } else { + mOffscreenCanvas = new Canvas(mOffscreenBuffer); + } + } + private void onDrawKeyboard(final Canvas canvas) { if (mKeyboard == null) return; diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index d0fecf060..59a92d625 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -23,6 +23,7 @@ import android.graphics.Paint; import android.graphics.Paint.Align; import android.os.Message; import android.text.TextUtils; +import android.util.AttributeSet; import android.util.SparseArray; import android.widget.RelativeLayout; @@ -49,6 +50,9 @@ public class PreviewPlacerView extends RelativeLayout { private final SparseArray<PointerTracker> mPointers = new SparseArray<PointerTracker>(); private String mGestureFloatingPreviewText; + private int mLastPointerX; + private int mLastPointerY; + private boolean mDrawsGesturePreviewTrail; private boolean mDrawsGestureFloatingPreviewText; @@ -89,10 +93,16 @@ public class PreviewPlacerView extends RelativeLayout { } } - public PreviewPlacerView(Context context, TypedArray keyboardViewAttr) { + public PreviewPlacerView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.keyboardViewStyle); + } + + public PreviewPlacerView(Context context, AttributeSet attrs, int defStyle) { super(context); setWillNotDraw(false); + final TypedArray keyboardViewAttr = context.obtainStyledAttributes( + attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); final int gestureFloatingPreviewTextSize = keyboardViewAttr.getDimensionPixelSize( R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0); mGestureFloatingPreviewTextColor = keyboardViewAttr.getColor( @@ -117,6 +127,7 @@ public class PreviewPlacerView extends RelativeLayout { R.styleable.KeyboardView_gesturePreviewTrailColor, 0); final int gesturePreviewTrailWidth = keyboardViewAttr.getDimensionPixelSize( R.styleable.KeyboardView_gesturePreviewTrailWidth, 0); + keyboardViewAttr.recycle(); mGesturePaint = new Paint(); mGesturePaint.setAntiAlias(true); @@ -146,31 +157,30 @@ public class PreviewPlacerView extends RelativeLayout { public void invalidatePointer(PointerTracker tracker) { synchronized (mPointers) { mPointers.put(tracker.mPointerId, tracker); - // TODO: Should narrow the invalidate region. - invalidate(); } + mLastPointerX = tracker.getLastX(); + mLastPointerY = tracker.getLastY(); + // TODO: Should narrow the invalidate region. + invalidate(); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); - synchronized (mPointers) { - canvas.translate(mXOrigin, mYOrigin); - final int trackerCount = mPointers.size(); - boolean hasDrawnFloatingPreviewText = false; - for (int index = 0; index < trackerCount; index++) { - final PointerTracker tracker = mPointers.valueAt(index); - if (mDrawsGesturePreviewTrail) { + 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); } - // TODO: Figure out more cleaner way to draw gesture preview text. - if (mDrawsGestureFloatingPreviewText && !hasDrawnFloatingPreviewText) { - drawGestureFloatingPreviewText(canvas, tracker, mGestureFloatingPreviewText); - hasDrawnFloatingPreviewText = true; - } } - canvas.translate(-mXOrigin, -mYOrigin); } + if (mDrawsGestureFloatingPreviewText) { + drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText); + } + canvas.translate(-mXOrigin, -mYOrigin); } public void setGestureFloatingPreviewText(String gestureFloatingPreviewText) { @@ -186,15 +196,16 @@ public class PreviewPlacerView extends RelativeLayout { mDrawingHandler.cancelAllMessages(); } - private void drawGestureFloatingPreviewText(Canvas canvas, PointerTracker tracker, - String gestureFloatingPreviewText) { + private void drawGestureFloatingPreviewText(Canvas canvas, String gestureFloatingPreviewText) { if (TextUtils.isEmpty(gestureFloatingPreviewText)) { return; } final Paint paint = mTextPaint; - final int lastX = tracker.getLastX(); - final int lastY = tracker.getLastY(); + // TODO: Figure out how we should deal with the floating preview text with multiple moving + // fingers. + final int lastX = mLastPointerX; + final int lastY = mLastPointerY; final int textSize = (int)paint.getTextSize(); final int canvasWidth = canvas.getWidth(); diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index 048166807..01ba30077 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -39,7 +39,6 @@ public class AutoCorrection { } final CharSequence lowerCasedWord = word.toString().toLowerCase(); for (final String key : dictionaries.keySet()) { - if (key.equals(Dictionary.TYPE_WHITELIST)) continue; final Dictionary dictionary = dictionaries.get(key); // It's unclear how realistically 'dictionary' can be null, but the monkey is somehow // managing to get null in here. Presumably the language is changing to a language with @@ -64,7 +63,6 @@ public class AutoCorrection { } int maxFreq = -1; for (final String key : dictionaries.keySet()) { - if (key.equals(Dictionary.TYPE_WHITELIST)) continue; final Dictionary dictionary = dictionaries.get(key); if (null == dictionary) continue; final int tempFreq = dictionary.getFrequency(word); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 726c44cc1..2d9e0ce2c 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -64,18 +64,21 @@ public class BinaryDictionary extends Dictionary { private final SparseArray<DicTraverseSession> mDicTraverseSessions = new SparseArray<DicTraverseSession>(); + + // TODO: There should be a way to remove used DicTraverseSession objects from + // {@code mDicTraverseSessions}. private DicTraverseSession getTraverseSession(int traverseSessionId) { - DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId); - if (traverseSession == null) { - synchronized(mDicTraverseSessions) { + synchronized(mDicTraverseSessions) { + DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId); + if (traverseSession == null) { traverseSession = mDicTraverseSessions.get(traverseSessionId); if (traverseSession == null) { traverseSession = new DicTraverseSession(mLocale, mNativeDict); mDicTraverseSessions.put(traverseSessionId, traverseSession); } } + return traverseSession; } - return traverseSession; } /** @@ -209,18 +212,20 @@ public class BinaryDictionary extends Dictionary { } @Override - public synchronized void close() { - for (int i = 0; i < mDicTraverseSessions.size(); ++i) { - final int key = mDicTraverseSessions.keyAt(i); - final DicTraverseSession traverseSession = mDicTraverseSessions.get(key); - if (traverseSession != null) { - traverseSession.close(); + public void close() { + synchronized (mDicTraverseSessions) { + final int sessionsSize = mDicTraverseSessions.size(); + for (int index = 0; index < sessionsSize; ++index) { + final DicTraverseSession traverseSession = mDicTraverseSessions.valueAt(index); + if (traverseSession != null) { + traverseSession.close(); + } } } closeInternal(); } - private void closeInternal() { + private synchronized void closeInternal() { if (mNativeDict != 0) { closeNative(mNativeDict); mNativeDict = 0; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 063243e1b..dd11aaa37 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; + import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; @@ -23,6 +25,7 @@ import android.content.res.AssetFileDescriptor; import android.util.Log; import java.io.File; +import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; @@ -51,6 +54,9 @@ class BinaryDictionaryGetter { private static final String MAIN_DICTIONARY_CATEGORY = "main"; public static final String ID_CATEGORY_SEPARATOR = ":"; + // The key considered to read the version attribute in a dictionary file. + private static String VERSION_KEY = "version"; + // Prevents this from being instantiated private BinaryDictionaryGetter() {} @@ -336,6 +342,42 @@ class BinaryDictionaryGetter { return MAIN_DICTIONARY_CATEGORY.equals(idArray[0]); } + // ## HACK ## we prevent usage of a dictionary before version 18 for English only. The reason + // for this is, since those do not include whitelist entries, the new code with an old version + // of the dictionary would lose whitelist functionality. + private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) { + // Only for English - other languages didn't have a whitelist, hence this + // ad-hock ## HACK ## + if (!Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) return true; + + try { + // Read the version of the file + final RandomAccessFile raf = new RandomAccessFile(f, "r"); + final int magic = raf.readInt(); + if (magic != BinaryDictInputOutput.VERSION_2_MAGIC_NUMBER) { + return false; + } + final int formatVersion = raf.readInt(); + final int headerSize = raf.readInt(); + final HashMap<String, String> options = new HashMap<String, String>(); + BinaryDictInputOutput.populateOptionsFromFile(raf, headerSize, options); + final String version = options.get(VERSION_KEY); + if (null == version) { + // No version in the options : the format is unexpected + return false; + } + // Version 18 is the first one to include the whitelist + // Obviously this is a big ## HACK ## + return Integer.parseInt(version) >= 18; + } catch (java.io.FileNotFoundException e) { + return false; + } catch (java.io.IOException e) { + return false; + } catch (NumberFormatException e) { + return false; + } + } + /** * Returns a list of file addresses for a given locale, trying relevant methods in order. * @@ -366,14 +408,15 @@ class BinaryDictionaryGetter { // cachedWordLists may not be null, see doc for getCachedDictionaryList for (final File f : cachedWordLists) { final String wordListId = getWordListIdFromFileName(f.getName()); - if (isMainWordListId(wordListId)) { + final boolean canUse = f.canRead() && hackCanUseDictionaryFile(locale, f); + if (canUse && isMainWordListId(wordListId)) { foundMainDict = true; } if (!dictPackSettings.isWordListActive(wordListId)) continue; - if (f.canRead()) { + if (canUse) { fileList.add(AssetFileAddress.makeFromFileName(f.getPath())); } else { - Log.e(TAG, "Found a cached dictionary file but cannot read it"); + Log.e(TAG, "Found a cached dictionary file but cannot read or use it"); } } diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 2565dfc66..88d0c09dd 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -42,7 +42,6 @@ public abstract class Dictionary { public static final String TYPE_USER = "user"; // User history dictionary internal to LatinIME. public static final String TYPE_USER_HISTORY = "history"; - public static final String TYPE_WHITELIST ="whitelist"; protected final String mDictType; public Dictionary(final String dictType) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a4c82c9f7..aa2f185e8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1669,6 +1669,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen Utils.Stats.onSeparator((char)primaryCode, x, y); + mHandler.postUpdateShiftState(); return didAutoCorrect; } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 1f43c6d85..e9314084a 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -50,7 +50,6 @@ public class Suggest { private Dictionary mMainDictionary; private ContactsBinaryDictionary mContactsDict; - private WhitelistDictionary mWhiteListDictionary; private final ConcurrentHashMap<String, Dictionary> mDictionaries = new ConcurrentHashMap<String, Dictionary>(); @@ -74,21 +73,11 @@ public class Suggest { mLocale = locale; mMainDictionary = mainDict; addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_MAIN, mainDict); - initWhitelistAndAutocorrectAndPool(context, locale); - } - - private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) { - mWhiteListDictionary = new WhitelistDictionary(context, locale); - addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_WHITELIST, mWhiteListDictionary); } private void initAsynchronously(final Context context, final Locale locale, final SuggestInitializationListener listener) { resetMainDict(context, locale, listener); - - // TODO: read the whitelist and init the pool asynchronously too. - // initPool should be done asynchronously now that the pool is thread-safe. - initWhitelistAndAutocorrectAndPool(context, locale); } private static void addOrReplaceDictionary( @@ -216,15 +205,6 @@ public class Suggest { wordComposerForLookup, prevWordForBigram, proximityInfo)); } - final CharSequence whitelistedWordFromWhitelistDictionary = - mWhiteListDictionary.getWhitelistedWord(consideredWord); - if (whitelistedWordFromWhitelistDictionary != null) { - // MAX_SCORE ensures this will be considered strong enough to be auto-corrected - suggestionsSet.add(new SuggestedWordInfo(whitelistedWordFromWhitelistDictionary, - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST, - Dictionary.TYPE_WHITELIST)); - } - final CharSequence whitelistedWord; if (suggestionsSet.isEmpty()) { whitelistedWord = null; @@ -234,11 +214,6 @@ public class Suggest { whitelistedWord = suggestionsSet.first().mWord; } - // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid" - // but still autocorrected from - in the case the whitelist only capitalizes the word. - // The whitelist should be case-insensitive, so it's not possible to be consistent with - // a boolean flag. Right now this is handled with a slight hack in - // WhitelistDictionary#shouldForciblyAutoCorrectFrom. final boolean allowsToBeAutoCorrected = (null != whitelistedWord && !whitelistedWord.equals(consideredWord)) || AutoCorrection.isNotAWord(mDictionaries, consideredWord, @@ -320,9 +295,10 @@ public class Suggest { // At second character typed, search the unigrams (scores being affected by bigrams) for (final String key : mDictionaries.keySet()) { - // Skip UserUnigramDictionary and WhitelistDictionary to lookup - if (key.equals(Dictionary.TYPE_USER_HISTORY) - || key.equals(Dictionary.TYPE_WHITELIST)) { + // Skip User history dictionary for lookup + // TODO: The user history dictionary should just override getSuggestionsWithSessionId + // to make sure it doesn't return anything and we should remove this test + if (key.equals(Dictionary.TYPE_USER_HISTORY)) { continue; } final Dictionary dictionary = mDictionaries.get(key); diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java deleted file mode 100644 index 14476dcf0..000000000 --- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import android.content.Context; -import android.content.res.Resources; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; - -import com.android.inputmethod.keyboard.ProximityInfo; -import com.android.inputmethod.latin.LocaleUtils.RunInLocale; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Locale; - -public class WhitelistDictionary extends ExpandableDictionary { - - private static final boolean DBG = LatinImeLogger.sDBG; - private static final String TAG = WhitelistDictionary.class.getSimpleName(); - - private final HashMap<String, Pair<Integer, String>> mWhitelistWords = - new HashMap<String, Pair<Integer, String>>(); - - // TODO: Conform to the async load contact of ExpandableDictionary - public WhitelistDictionary(final Context context, final Locale locale) { - super(context, Dictionary.TYPE_WHITELIST); - // TODO: Move whitelist dictionary into main dictionary. - final RunInLocale<Void> job = new RunInLocale<Void>() { - @Override - protected Void job(Resources res) { - initWordlist(res.getStringArray(R.array.wordlist_whitelist)); - return null; - } - }; - job.runInLocale(context.getResources(), locale); - } - - private void initWordlist(String[] wordlist) { - mWhitelistWords.clear(); - final int N = wordlist.length; - if (N % 3 != 0) { - if (DBG) { - Log.d(TAG, "The number of the whitelist is invalid."); - } - return; - } - try { - for (int i = 0; i < N; i += 3) { - final int score = Integer.valueOf(wordlist[i]); - final String before = wordlist[i + 1]; - final String after = wordlist[i + 2]; - if (before != null && after != null) { - mWhitelistWords.put( - before.toLowerCase(), new Pair<Integer, String>(score, after)); - addWord(after, null /* shortcut */, score); - } - } - } catch (NumberFormatException e) { - if (DBG) { - Log.d(TAG, "The score of the word is invalid."); - } - } - } - - public String getWhitelistedWord(String before) { - if (before == null) return null; - final String lowerCaseBefore = before.toLowerCase(); - if(mWhitelistWords.containsKey(lowerCaseBefore)) { - if (DBG) { - Log.d(TAG, "--- found whitelistedWord: " + lowerCaseBefore); - } - return mWhitelistWords.get(lowerCaseBefore).second; - } - return null; - } - - @Override - public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, - final CharSequence prevWord, final ProximityInfo proximityInfo) { - // Whitelist does not supply any suggestions or predictions. - return null; - } - - // See LatinIME#updateSuggestions. This breaks in the (queer) case that the whitelist - // lists that word a should autocorrect to word b, and word c would autocorrect to - // an upper-cased version of a. In this case, the way this return value is used would - // remove the first candidate when the user typed the upper-cased version of A. - // Example : abc -> def and xyz -> Abc - // A user typing Abc would experience it being autocorrected to something else (not - // necessarily def). - // There is no such combination in the whitelist at the time and there probably won't - // ever be - it doesn't make sense. But still. - public boolean shouldForciblyAutoCorrectFrom(CharSequence word) { - if (TextUtils.isEmpty(word)) return false; - final String correction = getWhitelistedWord(word.toString()); - if (TextUtils.isEmpty(correction)) return false; - return !correction.equals(word); - } - - // Leave implementation of getWords and isValidWord to the superclass. - // The words have been added to the ExpandableDictionary with addWord() inside initWordlist. -} diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 7f042335a..b23b7db34 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -124,7 +124,7 @@ public class BinaryDictInputOutput { */ private static final int VERSION_1_MAGIC_NUMBER = 0x78B1; - private static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE; + public static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE; private static final int MINIMUM_SUPPORTED_VERSION = 1; private static final int MAXIMUM_SUPPORTED_VERSION = 2; private static final int NOT_A_VERSION_NUMBER = -1; @@ -1328,6 +1328,21 @@ public class BinaryDictInputOutput { } /** + * Reads options from a file and populate a map with their contents. + * + * 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); + options.put(key, value); + } + } + + /** * Reads a random access file and returns the memory representation of the dictionary. * * This high-level method takes a binary file and reads its contents, populating a @@ -1358,11 +1373,7 @@ public class BinaryDictInputOutput { } else { headerSize = (source.readUnsignedByte() << 24) + (source.readUnsignedByte() << 16) + (source.readUnsignedByte() << 8) + source.readUnsignedByte(); - while (source.getFilePointer() < headerSize) { - final String key = CharEncoding.readString(source); - final String value = CharEncoding.readString(source); - options.put(key, value); - } + populateOptionsFromFile(source, headerSize, options); source.seek(headerSize); } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 3bdfe1f27..d05dc021a 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -35,7 +35,6 @@ import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary; import com.android.inputmethod.latin.UserBinaryDictionary; -import com.android.inputmethod.latin.WhitelistDictionary; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -67,8 +66,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService Collections.synchronizedMap(new TreeMap<String, DictionaryPool>()); private Map<String, UserBinaryDictionary> mUserDictionaries = Collections.synchronizedMap(new TreeMap<String, UserBinaryDictionary>()); - private Map<String, Dictionary> mWhitelistDictionaries = - Collections.synchronizedMap(new TreeMap<String, Dictionary>()); private ContactsBinaryDictionary mContactsDictionary; // The threshold for a candidate to be offered as a suggestion. @@ -366,8 +363,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService final Map<String, UserBinaryDictionary> oldUserDictionaries = mUserDictionaries; mUserDictionaries = Collections.synchronizedMap(new TreeMap<String, UserBinaryDictionary>()); - final Map<String, Dictionary> oldWhitelistDictionaries = mWhitelistDictionaries; - mWhitelistDictionaries = Collections.synchronizedMap(new TreeMap<String, Dictionary>()); new Thread("spellchecker_close_dicts") { @Override public void run() { @@ -377,9 +372,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService for (Dictionary dict : oldUserDictionaries.values()) { dict.close(); } - for (Dictionary dict : oldWhitelistDictionaries.values()) { - dict.close(); - } synchronized (mUseContactsLock) { if (null != mContactsDictionary) { // The synchronously loaded contacts dictionary should have been in one @@ -423,12 +415,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService mUserDictionaries.put(localeStr, userDictionary); } dictionaryCollection.addDictionary(userDictionary); - Dictionary whitelistDictionary = mWhitelistDictionaries.get(localeStr); - if (null == whitelistDictionary) { - whitelistDictionary = new WhitelistDictionary(this, locale); - mWhitelistDictionaries.put(localeStr, whitelistDictionary); - } - dictionaryCollection.addDictionary(whitelistDictionary); synchronized (mUseContactsLock) { if (mUseContactsDictionary) { if (null == mContactsDictionary) { |