diff options
26 files changed, 418 insertions, 135 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index bb49f4758..d93bf5533 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -1899,9 +1899,10 @@ public final class KeyboardTextsSet { /* 47 */ "\u201C,\u201D,\u201E", /* 48 */ "!text/single_laqm_raqm_rtl", /* 49 */ "!text/double_laqm_raqm_rtl", - /* 50~ */ - null, null, null, - /* ~52 */ + /* 50 */ null, + // U+20AA: "₪" NEW SHEQEL SIGN + /* 51 */ "\u20AA", + /* 52 */ null, /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(|),)|(", // U+2605: "★" BLACK STAR /* 54 */ "\u2605", diff --git a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java index 269b3a299..55df263fe 100644 --- a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java +++ b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java @@ -19,10 +19,11 @@ package com.android.inputmethod.latin; import android.content.Context; import android.util.Log; +import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.makedict.Ver3DictEncoder; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; // TODO: Quit extending Dictionary after implementing dynamic binary dictionary. @@ -49,32 +50,21 @@ abstract public class AbstractDictionaryWriter extends Dictionary { abstract public void removeBigramWords(final String word0, final String word1); - abstract protected void writeBinaryDictionary(final FileOutputStream out) + abstract protected void writeDictionary(final DictEncoder dictEncoder) throws IOException, UnsupportedFormatException; public void write(final String fileName) { final String tempFileName = fileName + ".temp"; final File file = new File(mContext.getFilesDir(), fileName); final File tempFile = new File(mContext.getFilesDir(), tempFileName); - FileOutputStream out = null; try { - out = new FileOutputStream(tempFile); - writeBinaryDictionary(out); - out.flush(); - out.close(); + final DictEncoder dictEncoder = new Ver3DictEncoder(file); + writeDictionary(dictEncoder); tempFile.renameTo(file); } catch (IOException e) { Log.e(TAG, "IO exception while writing file", e); } catch (UnsupportedFormatException e) { Log.e(TAG, "Unsupported format", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - // ignore - } - } } } } diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java index b3a572809..a97e053d0 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java +++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java @@ -20,7 +20,7 @@ import android.content.Context; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.makedict.BinaryDictEncoderUtils; +import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; @@ -28,7 +28,6 @@ import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.utils.CollectionUtils; -import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -85,9 +84,9 @@ public class DictionaryWriter extends AbstractDictionaryWriter { } @Override - protected void writeBinaryDictionary(final FileOutputStream out) + protected void writeDictionary(final DictEncoder dictEncoder) throws IOException, UnsupportedFormatException { - BinaryDictEncoderUtils.writeDictionaryBinary(out, mFusionDictionary, FORMAT_OPTIONS); + dictEncoder.writeDictionary(mFusionDictionary, FORMAT_OPTIONS); } @Override diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d67195b0d..3a2de5927 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -73,6 +73,7 @@ import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.define.ProductionFlag; +import com.android.inputmethod.latin.personalization.PersonalizationDictionary; import com.android.inputmethod.latin.personalization.PersonalizationDictionaryHelper; import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegister; import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary; @@ -173,6 +174,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private UserBinaryDictionary mUserDictionary; private UserHistoryPredictionDictionary mUserHistoryPredictionDictionary; private PersonalizationPredictionDictionary mPersonalizationPredictionDictionary; + private PersonalizationDictionary mPersonalizationDictionary; private boolean mIsUserDictionaryAvailable; private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; @@ -567,6 +569,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mUserHistoryPredictionDictionary = PersonalizationDictionaryHelper .getUserHistoryPredictionDictionary(this, localeStr, prefs); newSuggest.setUserHistoryPredictionDictionary(mUserHistoryPredictionDictionary); + mPersonalizationDictionary = PersonalizationDictionaryHelper + .getPersonalizationDictionary(this, localeStr, prefs); + newSuggest.setPersonalizationDictionary(mPersonalizationDictionary); mPersonalizationPredictionDictionary = PersonalizationDictionaryHelper .getPersonalizationPredictionDictionary(this, localeStr, prefs); newSuggest.setPersonalizationPredictionDictionary(mPersonalizationPredictionDictionary); diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 35920f8cb..a031bb3be 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -169,7 +169,6 @@ public final class RichInputConnection { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); mCommittedTextBeforeComposingText.append(mComposingText); - mExpectedCursorPosition += mComposingText.length(); mComposingText.setLength(0); if (null != mIC) { mIC.finishComposingText(); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 8766e0fc1..c8a151a6c 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -24,6 +24,7 @@ import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.personalization.PersonalizationDictionary; import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary; import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary; import com.android.inputmethod.latin.settings.Settings; @@ -200,6 +201,12 @@ public final class Suggest { personalizationPredictionDictionary); } + public void setPersonalizationDictionary( + final PersonalizationDictionary personalizationDictionary) { + addOrReplaceDictionaryInternal(Dictionary.TYPE_PERSONALIZATION, + personalizationDictionary); + } + public void setAutoCorrectionThreshold(float threshold) { mAutoCorrectionThreshold = threshold; } diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java index 3fe3ae6ce..40effb5e3 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java @@ -108,7 +108,7 @@ public class BinaryDictEncoderUtils { * like address lists do. */ static int getShortcutListSize(final ArrayList<WeightedString> shortcutList) { - if (null == shortcutList) return 0; + if (null == shortcutList || shortcutList.isEmpty()) return 0; int size = FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE; for (final WeightedString shortcut : shortcutList) { size += getShortcutSize(shortcut); @@ -601,8 +601,9 @@ public class BinaryDictEncoderUtils { private static byte makeCharGroupFlags(final CharGroup group, final int groupAddress, final int childrenOffset, final FormatOptions formatOptions) { return (byte) makeCharGroupFlags(group.mChars.length > 1, group.mFrequency >= 0, - getByteSize(childrenOffset), group.mShortcutTargets != null, group.mBigrams != null, - group.mIsNotAWord, group.mIsBlacklistEntry, formatOptions); + getByteSize(childrenOffset), + group.mShortcutTargets != null && !group.mShortcutTargets.isEmpty(), + group.mBigrams != null, group.mIsNotAWord, group.mIsBlacklistEntry, formatOptions); } /** @@ -795,7 +796,7 @@ public class BinaryDictEncoderUtils { groupAddress += shift; // Write shortcuts - if (null != group.mShortcutTargets) { + if (null != group.mShortcutTargets && !group.mShortcutTargets.isEmpty()) { final int indexOfShortcutByteSize = index; index += FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE; groupAddress += FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE; @@ -911,13 +912,11 @@ public class BinaryDictEncoderUtils { /** * Dumps a FusionDictionary to a file. * - * This is the public entry point to write a dictionary to a file. - * * @param destination the stream to write the binary data to. * @param dict the dictionary to write. * @param formatOptions file format options. */ - public static void writeDictionaryBinary(final OutputStream destination, + /* package */ static void writeDictionaryBinary(final OutputStream destination, final FusionDictionary dict, final FormatOptions formatOptions) throws IOException, UnsupportedFormatException { diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java index 8e1e14e9e..9f8842c9f 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -375,7 +375,7 @@ public final class BinaryDictIOUtils { * @param info the char group info to be written. * @return the size written, in bytes. */ - public static int writeCharGroup(final OutputStream destination, final CharGroupInfo info) + private static int writeCharGroup(final OutputStream destination, final CharGroupInfo info) throws IOException { int size = FormatSpec.GROUP_FLAGS_SIZE; destination.write((byte)info.mFlags); @@ -507,29 +507,6 @@ public final class BinaryDictIOUtils { return size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE; } - /** - * Find a word using the Ver3DictDecoder. - * - * @param dictDecoder the dict reader - * @param word the word searched - * @return the found group - * @throws IOException - * @throws UnsupportedFormatException - */ - @UsedForTesting - public static CharGroupInfo findWordByBinaryDictReader(final Ver3DictDecoder dictDecoder, - final String word) throws IOException, UnsupportedFormatException { - int position = getTerminalPosition(dictDecoder, word); - final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); - if (position != FormatSpec.NOT_VALID_WORD) { - dictBuffer.position(0); - final FileHeader header = dictDecoder.readHeader(); - dictBuffer.position(position); - return dictDecoder.readPtNode(position, header.mFormatOptions); - } - return null; - } - private static final int HEADER_READING_BUFFER_SIZE = 16384; /** * Convenience method to read the header of a binary file. diff --git a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java new file mode 100644 index 000000000..89c982e7b --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.makedict; + +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; + +import java.io.IOException; + +/** + * An interface of binary dictionary encoder. + */ +public interface DictEncoder { + public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions) + throws IOException, UnsupportedFormatException; +} diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java index 8d1b02713..494bbfcf2 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java @@ -255,18 +255,26 @@ public class Ver3DictDecoder implements DictDecoder { childrenAddress += addressPointer; } addressPointer += BinaryDictIOUtils.getChildrenAddressSize(flags, options); - ArrayList<WeightedString> shortcutTargets = null; + final ArrayList<WeightedString> shortcutTargets; if (0 != (flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS)) { + // readShortcut will add shortcuts to shortcutTargets. + shortcutTargets = new ArrayList<WeightedString>(); addressPointer += PtNodeReader.readShortcut(mDictBuffer, shortcutTargets); + } else { + shortcutTargets = null; } - ArrayList<PendingAttribute> bigrams = null; + + final ArrayList<PendingAttribute> bigrams; if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) { bigrams = new ArrayList<PendingAttribute>(); addressPointer += PtNodeReader.readBigrams(mDictBuffer, bigrams, addressPointer); if (bigrams.size() >= FormatSpec.MAX_BIGRAMS_IN_A_GROUP) { MakedictLog.d("too many bigrams in a group."); } + } else { + bigrams = null; } + return new CharGroupInfo(ptNodePos, addressPointer, flags, characters, frequency, parentAddress, childrenAddress, shortcutTargets, bigrams); } diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java new file mode 100644 index 000000000..e81fd4514 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.makedict; + +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * An implementation of DictEncoder for version 3 binary dictionary. + */ +public class Ver3DictEncoder implements DictEncoder { + + private final File mDictFile; + private OutputStream mOutStream; + + public Ver3DictEncoder(final File dictFile) { + mDictFile = dictFile; + mOutStream = null; + } + + // This constructor is used only by BinaryDictOffdeviceUtilsTests. + // If you want to use this in the production code, you should consider keeping consistency of + // the interface of Ver3DictDecoder by using factory. + public Ver3DictEncoder(final OutputStream outStream) { + mDictFile = null; + mOutStream = outStream; + } + + private void openStream() throws FileNotFoundException { + mOutStream = new FileOutputStream(mDictFile); + } + + private void close() throws IOException { + if (mOutStream != null) { + mOutStream.close(); + mOutStream = null; + } + } + + @Override + public void writeDictionary(FusionDictionary dict, FormatOptions formatOptions) + throws IOException, UnsupportedFormatException { + if (mOutStream == null) { + openStream(); + } + BinaryDictEncoderUtils.writeDictionaryBinary(mOutStream, dict, formatOptions); + close(); + } +} diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java index b565b2f9f..d046da850 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java @@ -28,8 +28,10 @@ import com.android.inputmethod.latin.ExpandableDictionary; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; +import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.Ver3DictDecoder; +import com.android.inputmethod.latin.makedict.Ver3DictEncoder; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils; @@ -40,7 +42,6 @@ import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.Forge import java.io.File; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicReference; @@ -332,24 +333,9 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableDictiona final String fileName = mDynamicPredictionDictionary.getDictionaryFileName(); final File file = new File(mContext.getFilesDir(), fileName); - FileOutputStream out = null; - try { - out = new FileOutputStream(file); - UserHistoryDictIOUtils.writeDictionaryBinary(out, this, mBigramList, VERSION3); - out.flush(); - out.close(); - } catch (IOException e) { - Log.e(TAG, "IO Exception while writing file", e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - // ignore - } - } - } + final DictEncoder dictEncoder = new Ver3DictEncoder(file); + UserHistoryDictIOUtils.writeDictionary(dictEncoder, this, mBigramList, VERSION3); // Save the timestamp after we finish writing the binary dictionary. Settings.writeLastUserHistoryWriteTime(mPrefs, mLocale); @@ -403,7 +389,7 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableDictiona } public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) { - session.setPredictionDictionary(mLocale, this); + session.setPredictionDictionary(this); mSessions.add(session); session.onDictionaryReady(); } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java index 275ce2fdc..f257165cb 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java @@ -18,28 +18,32 @@ package com.android.inputmethod.latin.personalization; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary; +import com.android.inputmethod.latin.utils.CollectionUtils; import android.content.Context; +import android.content.SharedPreferences; + +import java.util.ArrayList; /** * This class is a dictionary for the personalized language model that uses binary dictionary. */ public class PersonalizationDictionary extends ExpandableBinaryDictionary { private static final String NAME = "personalization"; - - public static void registerUpdateListener(PersonalizationDictionaryUpdateSession listener) { - // TODO: Implement - } + private final ArrayList<PersonalizationDictionaryUpdateSession> mSessions = + CollectionUtils.newArrayList(); /** Locale for which this user history dictionary is storing words */ private final String mLocale; - // Singleton - private PersonalizationDictionary(final Context context, final String locale) { + public PersonalizationDictionary(final Context context, final String locale, + final SharedPreferences prefs) { // TODO: Make isUpdatable true. super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_PERSONALIZATION, false /* isUpdatable */); mLocale = locale; + // TODO: Restore last updated time + loadDictionary(); } @Override @@ -49,15 +53,21 @@ public class PersonalizationDictionary extends ExpandableBinaryDictionary { @Override protected boolean hasContentChanged() { - // TODO: Implement return false; } @Override protected boolean needsToReloadBeforeWriting() { - // TODO: Implement return false; } - // TODO: Implement + public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) { + session.setDictionary(this); + mSessions.add(session); + session.onDictionaryReady(); + } + + public void unRegisterUpdateSession(PersonalizationDictionaryUpdateSession session) { + mSessions.remove(session); + } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java index b4fd25024..6798f1360 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java @@ -35,7 +35,13 @@ public class PersonalizationDictionaryHelper { private static final ConcurrentHashMap<String, SoftReference<PersonalizationPredictionDictionary>> - sLangPersonalizationDictCache = CollectionUtils.newConcurrentHashMap(); + sLangPersonalizationPredictionDictCache = + CollectionUtils.newConcurrentHashMap(); + + private static final ConcurrentHashMap<String, + SoftReference<PersonalizationDictionary>> + sLangPersonalizationDictCache = + CollectionUtils.newConcurrentHashMap(); public static UserHistoryPredictionDictionary getUserHistoryPredictionDictionary( final Context context, final String locale, final SharedPreferences sp) { @@ -60,20 +66,45 @@ public class PersonalizationDictionaryHelper { } public static void registerPersonalizationDictionaryUpdateSession(final Context context, - final PersonalizationDictionaryUpdateSession session) { - final PersonalizationPredictionDictionary dictionary = - getPersonalizationPredictionDictionary(context, - context.getResources().getConfiguration().locale.toString(), + final PersonalizationDictionaryUpdateSession session, String locale) { + final PersonalizationPredictionDictionary predictionDictionary = + getPersonalizationPredictionDictionary(context, locale, + PreferenceManager.getDefaultSharedPreferences(context)); + predictionDictionary.registerUpdateSession(session); + final PersonalizationDictionary dictionary = + getPersonalizationDictionary(context, locale, PreferenceManager.getDefaultSharedPreferences(context)); dictionary.registerUpdateSession(session); } - public static PersonalizationPredictionDictionary getPersonalizationPredictionDictionary( + public static PersonalizationDictionary getPersonalizationDictionary( final Context context, final String locale, final SharedPreferences sp) { synchronized (sLangPersonalizationDictCache) { if (sLangPersonalizationDictCache.containsKey(locale)) { - final SoftReference<PersonalizationPredictionDictionary> ref = + final SoftReference<PersonalizationDictionary> ref = sLangPersonalizationDictCache.get(locale); + final PersonalizationDictionary dict = ref == null ? null : ref.get(); + if (dict != null) { + if (DEBUG) { + Log.w(TAG, "Use cached PersonalizationDictCache for " + locale); + } + return dict; + } + } + final PersonalizationDictionary dict = + new PersonalizationDictionary(context, locale, sp); + sLangPersonalizationDictCache.put( + locale, new SoftReference<PersonalizationDictionary>(dict)); + return dict; + } + } + + public static PersonalizationPredictionDictionary getPersonalizationPredictionDictionary( + final Context context, final String locale, final SharedPreferences sp) { + synchronized (sLangPersonalizationPredictionDictCache) { + if (sLangPersonalizationPredictionDictCache.containsKey(locale)) { + final SoftReference<PersonalizationPredictionDictionary> ref = + sLangPersonalizationPredictionDictCache.get(locale); final PersonalizationPredictionDictionary dict = ref == null ? null : ref.get(); if (dict != null) { if (DEBUG) { @@ -84,7 +115,7 @@ public class PersonalizationDictionaryHelper { } final PersonalizationPredictionDictionary dict = new PersonalizationPredictionDictionary(context, locale, sp); - sLangPersonalizationDictCache.put( + sLangPersonalizationPredictionDictCache.put( locale, new SoftReference<PersonalizationPredictionDictionary>(dict)); return dict; } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java index 77f0cdbfa..978804951 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin.personalization; +import com.android.inputmethod.latin.ExpandableBinaryDictionary; + import android.content.Context; import java.lang.ref.WeakReference; @@ -45,22 +47,41 @@ public abstract class PersonalizationDictionaryUpdateSession { } // TODO: Use a dynamic binary dictionary instead + public WeakReference<PersonalizationDictionary> mDictionary; public WeakReference<DynamicPredictionDictionaryBase> mPredictionDictionary; - public String mLocale; + public final String mLocale; + public PersonalizationDictionaryUpdateSession(String locale) { + mLocale = locale; + } public abstract void onDictionaryReady(); public abstract void onDictionaryClosed(Context context); - public void setPredictionDictionary(String locale, DynamicPredictionDictionaryBase dictionary) { + public void setDictionary(PersonalizationDictionary dictionary) { + mDictionary = new WeakReference<PersonalizationDictionary>(dictionary); + } + + public void setPredictionDictionary(DynamicPredictionDictionaryBase dictionary) { mPredictionDictionary = new WeakReference<DynamicPredictionDictionaryBase>(dictionary); - mLocale = locale; + } + + protected PersonalizationDictionary getDictionary() { + return mDictionary == null ? null : mDictionary.get(); } protected DynamicPredictionDictionaryBase getPredictionDictionary() { return mPredictionDictionary == null ? null : mPredictionDictionary.get(); } + private void unsetDictionary() { + final PersonalizationDictionary dictionary = getDictionary(); + if (dictionary == null) { + return; + } + dictionary.unRegisterUpdateSession(this); + } + private void unsetPredictionDictionary() { final DynamicPredictionDictionaryBase dictionary = getPredictionDictionary(); if (dictionary == null) { @@ -78,6 +99,7 @@ public abstract class PersonalizationDictionaryUpdateSession { } public void closeSession(Context context) { + unsetDictionary(); unsetPredictionDictionary(); onDictionaryClosed(context); } diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java index 771db3a47..9d3d8a5da 100644 --- a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java @@ -19,8 +19,8 @@ package com.android.inputmethod.latin.utils; import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.BinaryDictEncoderUtils; import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; +import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; @@ -30,7 +30,6 @@ import com.android.inputmethod.latin.makedict.Ver3DictDecoder; import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList; import java.io.IOException; -import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -57,12 +56,12 @@ public final class UserHistoryDictIOUtils { /** * Writes dictionary to file. */ - public static void writeDictionaryBinary(final OutputStream destination, + public static void writeDictionary(final DictEncoder dictEncoder, final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams, final FormatOptions formatOptions) { final FusionDictionary fusionDict = constructFusionDictionary(dict, bigrams); try { - BinaryDictEncoderUtils.writeDictionaryBinary(destination, fusionDict, formatOptions); + dictEncoder.writeDictionary(fusionDict, formatOptions); Log.d(TAG, "end writing"); } catch (IOException e) { Log.e(TAG, "IO exception while writing file", e); diff --git a/native/jni/Android.mk b/native/jni/Android.mk index a51fe3c03..bf188971e 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -71,14 +71,16 @@ LATIN_IME_CORE_SRC_FILES := \ header/header_policy.cpp \ header/header_reading_utils.cpp \ shortcut/shortcut_list_reading_utils.cpp \ - utils/byte_array_utils.cpp \ - utils/format_utils.cpp \ dictionary_structure_with_buffer_policy_factory.cpp \ dynamic_patricia_trie_node_reader.cpp \ dynamic_patricia_trie_policy.cpp \ dynamic_patricia_trie_reading_utils.cpp \ patricia_trie_policy.cpp \ patricia_trie_reading_utils.cpp) \ + $(addprefix suggest/policyimpl/dictionary/utils/, \ + byte_array_utils.cpp \ + extendable_buffer.cpp \ + format_utils.cpp) \ suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \ $(addprefix suggest/policyimpl/typing/, \ scoring_params.cpp \ diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h index 8ba057b20..0e5920f42 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h @@ -24,6 +24,7 @@ #include "suggest/policyimpl/dictionary/bigram/bigram_list_policy.h" #include "suggest/policyimpl/dictionary/header/header_policy.h" #include "suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/utils/extendable_buffer.h" #include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" namespace latinime { @@ -34,7 +35,7 @@ class DicNodeVector; class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { public: DynamicPatriciaTriePolicy(const MmappedBuffer *const buffer) - : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer()), + : mBuffer(buffer), mExtendableBuffer(), mHeaderPolicy(mBuffer->getBuffer()), mDictRoot(mBuffer->getBuffer() + mHeaderPolicy.getSize()), mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot) {} @@ -87,8 +88,10 @@ class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP; const MmappedBuffer *const mBuffer; + const ExtendableBuffer mExtendableBuffer; const HeaderPolicy mHeaderPolicy; // TODO: Consolidate mDictRoot. + // CAVEAT!: Be careful about array out of bound access with mDictRoot const uint8_t *const mDictRoot; const BigramListPolicy mBigramListPolicy; const ShortcutListPolicy mShortcutListPolicy; diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/extendable_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/extendable_buffer.cpp new file mode 100644 index 000000000..e55cc2410 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/extendable_buffer.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/utils/extendable_buffer.h" + +namespace latinime { + +const size_t ExtendableBuffer::INITIAL_BUFFER_SIZE = 16 * 1024; +const size_t ExtendableBuffer::MAX_BUFFER_SIZE = 1024 * 1024; +const size_t ExtendableBuffer::EXTEND_BUFFER_SIZE_STEP = 16 * 1024; + +} diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/extendable_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/extendable_buffer.h new file mode 100644 index 000000000..d902d19c8 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/extendable_buffer.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013, 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. + */ + +#ifndef LATINIME_EXTENDABLE_BUFFER_H +#define LATINIME_EXTENDABLE_BUFFER_H + +#include <cstddef> +#include <stdint.h> +#include <vector> + +#include "defines.h" + +namespace latinime { + +// This is used as a buffer that can be extended for updatable dictionaries. +class ExtendableBuffer { + public: + ExtendableBuffer() : mBuffer(INITIAL_BUFFER_SIZE), mUsedSize(0) {} + + AK_FORCE_INLINE uint8_t *getBuffer() { + return &mBuffer[0]; + } + + // Return if the buffer is successfully extended or not. + AK_FORCE_INLINE bool extendBuffer() { + if (mBuffer.size() + EXTEND_BUFFER_SIZE_STEP > MAX_BUFFER_SIZE) { + return false; + } + mBuffer.resize(mBuffer.size() + EXTEND_BUFFER_SIZE_STEP); + return true; + } + + AK_FORCE_INLINE int getAllocatedSize() const { + return mBuffer.size(); + } + + AK_FORCE_INLINE int getUsedSize() const { + return mUsedSize; + } + + AK_FORCE_INLINE void clear() { + mUsedSize = 0; + mBuffer.clear(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ExtendableBuffer); + + static const size_t INITIAL_BUFFER_SIZE; + static const size_t MAX_BUFFER_SIZE; + static const size_t EXTEND_BUFFER_SIZE_STEP; + + std::vector<uint8_t> mBuffer; + int mUsedSize; +}; +} +#endif /* LATINIME_MMAPED_BUFFER_H */ diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java index f30be97f3..5bf9143ed 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java @@ -22,19 +22,21 @@ import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import android.util.SparseArray; +import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; +import com.android.inputmethod.latin.utils.ByteArrayDictBuffer; import com.android.inputmethod.latin.utils.CollectionUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -54,6 +56,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private static final int UNIGRAM_FREQ = 10; private static final int BIGRAM_FREQ = 50; private static final int TOLERANCE_OF_BIGRAM_FREQ = 5; + private static final int NUM_OF_NODES_HAVING_SHORTCUTS = 50; + private static final int NUM_OF_SHORTCUTS = 5; private static final int USE_BYTE_ARRAY = 1; private static final int USE_BYTE_BUFFER = 2; @@ -64,6 +68,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private static final SparseArray<List<Integer>> sStarBigrams = CollectionUtils.newSparseArray(); private static final SparseArray<List<Integer>> sChainBigrams = CollectionUtils.newSparseArray(); + private static final Map<String, List<String>> sShortcuts = CollectionUtils.newHashMap(); private static final FormatSpec.FormatOptions VERSION2 = new FormatSpec.FormatOptions(2); private static final FormatSpec.FormatOptions VERSION3_WITHOUT_DYNAMIC_UPDATE = @@ -96,6 +101,16 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { for (int i = 1; i < sWords.size(); ++i) { sStarBigrams.get(0).add(i); } + + sShortcuts.clear(); + for (int i = 0; i < NUM_OF_NODES_HAVING_SHORTCUTS; ++i) { + final int from = Math.abs(random.nextInt()) % sWords.size(); + sShortcuts.put(sWords.get(from), new ArrayList<String>()); + for (int j = 0; j < NUM_OF_SHORTCUTS; ++j) { + final int to = Math.abs(random.nextInt()) % sWords.size(); + sShortcuts.get(sWords.get(from)).add(sWords.get(to)); + } + } } private int[] generateCodePointSet(final int codePointSetSize, final Random random) { @@ -105,7 +120,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { if (r < 0) continue; // Don't insert 0~0x20, but insert any other code point. // Code points are in the range 0~0x10FFFF. - final int candidateCodePoint = (int)(0x20 + r % (Character.MAX_CODE_POINT - 0x20)); + final int candidateCodePoint = 0x20 + r % (Character.MAX_CODE_POINT - 0x20); // Code points between MIN_ and MAX_SURROGATE are not valid on their own. if (candidateCodePoint >= Character.MIN_SURROGATE && candidateCodePoint <= Character.MAX_SURROGATE) continue; @@ -204,17 +219,14 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { long now = -1, diff = -1; try { - final FileOutputStream out = new FileOutputStream(file); + final DictEncoder dictEncoder = new Ver3DictEncoder(file); now = System.currentTimeMillis(); // If you need to dump the dict to a textual file, uncomment the line below and the // function above // dumpToCombinedFileForDebug(file, "/tmp/foo"); - BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, formatOptions); + dictEncoder.writeDictionary(dict, formatOptions); diff = System.currentTimeMillis() - now; - - out.flush(); - out.close(); } catch (IOException e) { Log.e(TAG, "IO exception while writing file", e); } catch (UnsupportedFormatException e) { @@ -247,6 +259,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { // check shortcut if (shortcutMap != null) { for (final Map.Entry<String, List<String>> entry : shortcutMap.entrySet()) { + assertTrue(words.contains(entry.getKey())); final CharGroup group = FusionDictionary.findWordInTree(dict.mRootNodeArray, entry.getKey()); for (final String word : entry.getValue()) { @@ -325,6 +338,28 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { formatOptions, "chain")); results.add(runReadAndWrite(sWords, sStarBigrams, null /* shortcuts */, bufferType, formatOptions, "star")); + results.add(runReadAndWrite(sWords, sEmptyBigrams, sShortcuts, bufferType, formatOptions, + "unigram with shortcuts")); + results.add(runReadAndWrite(sWords, sChainBigrams, sShortcuts, bufferType, formatOptions, + "chain with shortcuts")); + results.add(runReadAndWrite(sWords, sStarBigrams, sShortcuts, bufferType, formatOptions, + "star with shortcuts")); + } + + // Unit test for CharEncoding.readString and CharEncoding.writeString. + public void testCharEncoding() { + // the max length of a word in sWords is less than 50. + // See generateWords. + final byte[] buffer = new byte[50 * 3]; + final DictBuffer dictBuffer = new ByteArrayDictBuffer(buffer); + for (final String word : sWords) { + Log.d("testReadAndWriteString", "write : " + word); + Arrays.fill(buffer, (byte)0); + CharEncoding.writeString(buffer, 0, word); + dictBuffer.position(0); + final String str = CharEncoding.readString(dictBuffer); + assertEquals(word, str); + } } public void testReadAndWriteWithByteBuffer() { diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java index 68976a7ca..bfdc0407a 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java @@ -161,13 +161,35 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { return position; } + /** + * Find a word using the Ver3DictDecoder. + * + * @param dictDecoder the dict decoder + * @param word the word searched + * @return the found group + * @throws IOException + * @throws UnsupportedFormatException + */ + private static CharGroupInfo findWordByBinaryDictReader(final Ver3DictDecoder dictDecoder, + final String word) throws IOException, UnsupportedFormatException { + int position = BinaryDictIOUtils.getTerminalPosition(dictDecoder, word); + final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); + if (position != FormatSpec.NOT_VALID_WORD) { + dictBuffer.position(0); + final FileHeader header = dictDecoder.readHeader(); + dictBuffer.position(position); + return dictDecoder.readPtNode(position, header.mFormatOptions); + } + return null; + } + private CharGroupInfo findWordFromFile(final File file, final String word) { final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(file); CharGroupInfo info = null; try { dictDecoder.openDictBuffer( new Ver3DictDecoder.DictionaryBufferFromReadOnlyByteBufferFactory()); - info = BinaryDictIOUtils.findWordByBinaryDictReader(dictDecoder, word); + info = findWordByBinaryDictReader(dictDecoder, word); } catch (IOException e) { } catch (UnsupportedFormatException e) { } @@ -252,9 +274,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { dict.add("abcd", 10, null, false); try { - final FileOutputStream out = new FileOutputStream(file); - BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, FORMAT_OPTIONS); - out.close(); + final DictEncoder dictEncoder = new Ver3DictEncoder(file); + dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } catch (UnsupportedFormatException e) { @@ -304,9 +325,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { dict.add("efgh", 15, null, false); try { - final FileOutputStream out = new FileOutputStream(file); - BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, FORMAT_OPTIONS); - out.close(); + final DictEncoder dictEncoder = new Ver3DictEncoder(file); + dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } catch (UnsupportedFormatException e) { @@ -342,9 +362,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { dict.add("initial", 10, null, false); try { - final FileOutputStream out = new FileOutputStream(file); - BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, FORMAT_OPTIONS); - out.close(); + final DictEncoder dictEncoder = new Ver3DictEncoder(file); + dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); } catch (IOException e) { assertTrue(false); } catch (UnsupportedFormatException e) { diff --git a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java index eca12c0d8..7b3a01ccf 100644 --- a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java @@ -21,17 +21,18 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; +import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup; import com.android.inputmethod.latin.makedict.Ver3DictDecoder; +import com.android.inputmethod.latin.makedict.Ver3DictEncoder; import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList; import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface; import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener; import java.io.File; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -136,14 +137,8 @@ public class UserHistoryDictIOUtilsTests extends AndroidTestCase private void writeDictToFile(final File file, final UserHistoryDictionaryBigramList bigramList) { - try { - final FileOutputStream out = new FileOutputStream(file); - UserHistoryDictIOUtils.writeDictionaryBinary(out, this, bigramList, FORMAT_OPTIONS); - out.flush(); - out.close(); - } catch (IOException e) { - Log.e(TAG, "IO exception while writing file", e); - } + final DictEncoder dictEncoder = new Ver3DictEncoder(file); + UserHistoryDictIOUtils.writeDictionary(dictEncoder, this, bigramList, FORMAT_OPTIONS); } private void readDictFromFile(final File file, final OnAddWordListener listener) { diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java index fee445389..6c1a9de58 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java @@ -17,18 +17,18 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils; -import com.android.inputmethod.latin.makedict.BinaryDictEncoderUtils; +import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.MakedictLog; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.Ver3DictDecoder; +import com.android.inputmethod.latin.makedict.Ver3DictEncoder; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; @@ -358,8 +358,8 @@ public class DictionaryMaker { throws FileNotFoundException, IOException, UnsupportedFormatException { final File outputFile = new File(outputFilename); final FormatSpec.FormatOptions formatOptions = new FormatSpec.FormatOptions(version); - BinaryDictEncoderUtils.writeDictionaryBinary(new FileOutputStream(outputFilename), dict, - formatOptions); + final DictEncoder dictEncoder = new Ver3DictEncoder(outputFile); + dictEncoder.writeDictionary(dict, formatOptions); } /** diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java index da51387be..2b2661a0c 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java @@ -17,13 +17,14 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils; -import com.android.inputmethod.latin.makedict.BinaryDictEncoderUtils; +import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.Ver3DictDecoder; +import com.android.inputmethod.latin.makedict.Ver3DictEncoder; import junit.framework.TestCase; @@ -53,12 +54,13 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { final File dst = File.createTempFile("testGetRawDict", ".tmp"); dst.deleteOnExit(); + final OutputStream out = Compress.getCompressedStream( Compress.getCompressedStream( Compress.getCompressedStream( new BufferedOutputStream(new FileOutputStream(dst))))); - - BinaryDictEncoderUtils.writeDictionaryBinary(out, dict, new FormatOptions(2, false)); + final DictEncoder dictEncoder = new Ver3DictEncoder(out); + dictEncoder.writeDictionary(dict, new FormatOptions(2, false)); // Test for an actually compressed dictionary and its contents final BinaryDictOffdeviceUtils.DecoderChainSpec decodeSpec = diff --git a/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml index 9d2e01ebd..e5d0ebf4d 100644 --- a/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml @@ -52,4 +52,6 @@ <string name="double_quotes">“,”,„</string> <string name="single_angle_quotes">!text/single_laqm_raqm_rtl</string> <string name="double_angle_quotes">!text/double_laqm_raqm_rtl</string> + <!-- U+20AA: "₪" NEW SHEQEL SIGN --> + <string name="keylabel_for_currency_generic">₪</string> </resources> |