diff options
Diffstat (limited to 'java/src')
7 files changed, 142 insertions, 49 deletions
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..9e9c9e29a 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; @@ -89,10 +90,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 +124,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); 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/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 884e6db29..c20f3a3a9 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2001,6 +2001,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) { if (TextUtils.isEmpty(suggestion)) return null; + if (mSuggest == null) return null; // If correction is not enabled, we don't add words to the user history dictionary. // That's to avoid unintended additions in some sensitive fields, or fields that diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 3bb670c9a..d516e72ad 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -52,14 +52,14 @@ public class UserHistoryDictionary extends ExpandableDictionary { private static final int FREQUENCY_FOR_TYPED = 2; /** Maximum number of pairs. Pruning will start when databases goes above this number. */ - private static int sMaxHistoryBigrams = 10000; + public static final int sMaxHistoryBigrams = 10000; /** * When it hits maximum bigram pair, it will delete until you are left with * only (sMaxHistoryBigrams - sDeleteHistoryBigrams) pairs. * Do not keep this number small to avoid deleting too often. */ - private static int sDeleteHistoryBigrams = 1000; + public static final int sDeleteHistoryBigrams = 1000; /** * Database version should increase if the database structure changes @@ -109,12 +109,8 @@ public class UserHistoryDictionary extends ExpandableDictionary { private static DatabaseHelper sOpenHelper = null; - public void setDatabaseMax(int maxHistoryBigram) { - sMaxHistoryBigrams = maxHistoryBigram; - } - - public void setDatabaseDelete(int deleteHistoryBigram) { - sDeleteHistoryBigrams = deleteHistoryBigram; + public String getLocale() { + return mLocale; } public synchronized static UserHistoryDictionary getInstance( @@ -502,9 +498,11 @@ public class UserHistoryDictionary extends ExpandableDictionary { needsToSave(fc, isValid, addLevel0Bigram)) { freq = fc; } else { + // Delete this entry freq = -1; } } else { + // Delete this entry freq = -1; } } @@ -541,6 +539,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { getContentValues(word1, word2, mLocale)); pairId = pairIdLong.intValue(); } + // Eliminate freq == 0 because that word is profanity. if (freq > 0) { if (PROFILE_SAVE_RESTORE) { ++profInsert; diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 2c3eee74c..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; @@ -783,10 +783,10 @@ public class BinaryDictInputOutput { // their lower bound and exclude their higher bound so we need to have the first step // start at exactly 1 unit higher than floor(unigramFreq + half a step). // Note : to reconstruct the score, the dictionary reader will need to divide - // MAX_TERMINAL_FREQUENCY - unigramFreq by 16.5 likewise, and add - // (discretizedFrequency + 0.5) times this value to get the median value of the step, - // which is the best approximation. This is how we get the most precise result with - // only four bits. + // MAX_TERMINAL_FREQUENCY - unigramFreq by 16.5 likewise to get the value of the step, + // and add (discretizedFrequency + 0.5 + 0.5) times this value to get the best + // approximation. (0.5 to get the first step start, and 0.5 to get the middle of the + // step pointed by the discretized frequency. final float stepSize = (MAX_TERMINAL_FREQUENCY - unigramFrequency) / (1.5f + MAX_BIGRAM_FREQUENCY); final float firstStepStart = 1 + unigramFrequency + (stepSize / 2.0f); @@ -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); } @@ -1410,4 +1421,22 @@ public class BinaryDictInputOutput { return false; } } + + /** + * Calculate bigram frequency from compressed value + * + * @see #makeBigramFlags + * + * @param unigramFrequency + * @param bigramFrequency compressed frequency + * @return approximate bigram frequency + */ + public static int reconstructBigramFrequency(final int unigramFrequency, + final int bigramFrequency) { + final float stepSize = (MAX_TERMINAL_FREQUENCY - unigramFrequency) + / (1.5f + MAX_BIGRAM_FREQUENCY); + final float resultFreqFloat = (float)unigramFrequency + + stepSize * (bigramFrequency + 1.0f); + return (int)resultFreqFloat; + } } |