diff options
-rw-r--r-- | java/res/values/attrs.xml | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/KeyboardView.java | 4 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java | 18 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java | 1 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java | 41 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java | 25 | ||||
-rw-r--r-- | native/jni/src/binary_format.h | 9 | ||||
-rw-r--r-- | native/jni/src/correction.cpp | 26 | ||||
-rw-r--r-- | native/jni/src/correction.h | 14 | ||||
-rw-r--r-- | native/jni/src/defines.h | 2 | ||||
-rw-r--r-- | native/jni/src/unigram_dictionary.cpp | 31 | ||||
-rw-r--r-- | tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl | 18 |
12 files changed, 139 insertions, 52 deletions
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index c78013f73..e14633a2e 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -64,7 +64,7 @@ <attr name="keyShiftedLetterHintRatio" format="float" /> <!-- Horizontal padding of left/right aligned key label to the edge of the key. --> <attr name="keyLabelHorizontalPadding" format="dimension" /> - <!-- Top and right padding of hint letter to the edge of the key.--> + <!-- Right padding of hint letter to the edge of the key.--> <attr name="keyHintLetterPadding" format="dimension" /> <!-- Bottom padding of popup hint letter "..." to the edge of the key.--> <attr name="keyPopupHintLetterPadding" format="dimension" /> diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index d5bd7fda3..4a9135310 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -662,10 +662,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { hintY = -mFontMetrics.top + params.mKeyShiftedLetterHintPadding; paint.setTextAlign(Align.CENTER); } else { // key.hasHintLetter() - // The hint label is placed at top-right corner of the key. Used mainly on phone. + // The hint letter is placed at top-right corner of the key. Used mainly on phone. hintX = keyWidth - params.mKeyHintLetterPadding - getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint) / 2; - hintY = -paint.ascent() + params.mKeyHintLetterPadding; + hintY = -paint.ascent(); paint.setTextAlign(Align.CENTER); } canvas.drawText(hint, 0, hint.length(), hintX, hintY, paint); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index d0f27a9a8..9dc1786c7 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -25,7 +25,23 @@ import java.util.HashMap; /** * !!!!! DO NOT EDIT THIS FILE !!!!! - * This file is generated by tools/maketext. + * + * This file is generated by tools/maketext. The base template file is + * tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl + * + * This file must be updated when any text resources in keyboard layout files have been changed. + * These text resources are referred as "!text/<resource_name>" in keyboard XML definitions, + * and should be defined in + * tools/maketext/res/values-<locale>/donottranslate-more-keys.xml + * + * To update this file, please run the following commands. + * $ cd $ANDROID_BUILD_TOP + * $ mmm packages/inputmethods/LatinIME/tools/maketext + * $ maketext -java packages/inputmethods/LatinIME/java/src + * + * The updated source file will be generated to the following path (this file). + * packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/ + * KeyboardTextsSet.java */ public final class KeyboardTextsSet { // Language to texts map. diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java index 613c20304..994b917a7 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -366,6 +366,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { final Preference pref = mSubtypePrefGroup.getPreference(i); if (pref instanceof SubtypePreference) { final InputMethodSubtype subtype = ((SubtypePreference)pref).getSubtype(); + if (subtype == null) continue; if (sb.length() > 0) { sb.append(AdditionalSubtype.PREF_SUBTYPE_SEPARATOR); } diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 97df98e34..cc98010fb 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -174,6 +174,13 @@ public class BinaryDictInputOutput { private static final int MAX_TERMINAL_FREQUENCY = 255; + // Arbitrary limit to how much passes we consider address size compression should + // terminate in. At the time of this writing, our largest dictionary completes + // compression in five passes. + // If the number of passes exceeds this number, makedict bails with an exception on + // suspicion that a bug might be causing an infinite loop. + private static final int MAX_PASSES = 24; + /** * A class grouping utility function for our specific character encoding. */ @@ -510,14 +517,22 @@ public class BinaryDictInputOutput { * Each node stores its tentative address. During dictionary address computing, these * are not final, but they can be used to compute the node size (the node size depends * on the address of the children because the number of bytes necessary to store an - * address depends on its numeric value. + * address depends on its numeric value. The return value indicates whether the node + * contents (as in, any of the addresses stored in the cache fields) have changed with + * respect to their previous value. * * @param node the node to compute the size of. * @param dict the dictionary in which the word/attributes are to be found. + * @return false if none of the cached addresses inside the node changed, true otherwise. */ - private static void computeActualNodeSize(Node node, FusionDictionary dict) { + private static boolean computeActualNodeSize(Node node, FusionDictionary dict) { + boolean changed = false; int size = getGroupCountSize(node); for (CharGroup group : node.mData) { + if (group.mCachedAddress != node.mCachedAddress + size) { + changed = true; + group.mCachedAddress = node.mCachedAddress + size; + } int groupSize = GROUP_FLAGS_SIZE + getGroupCharactersSize(group); if (group.isTerminal()) groupSize += GROUP_FREQUENCY_SIZE; if (null != group.mChildren) { @@ -538,7 +553,11 @@ public class BinaryDictInputOutput { group.mCachedSize = groupSize; size += groupSize; } - node.mCachedSize = size; + if (node.mCachedSize != size) { + node.mCachedSize = size; + changed = true; + } + return changed; } /** @@ -594,13 +613,14 @@ public class BinaryDictInputOutput { changesDone = false; for (Node n : flatNodes) { final int oldNodeSize = n.mCachedSize; - computeActualNodeSize(n, dict); + final boolean changed = computeActualNodeSize(n, dict); final int newNodeSize = n.mCachedSize; if (oldNodeSize < newNodeSize) throw new RuntimeException("Increased size ?!"); - if (oldNodeSize != newNodeSize) changesDone = true; + changesDone |= changed; } stackNodes(flatNodes); ++passes; + if (passes > MAX_PASSES) throw new RuntimeException("Too many passes - probably a bug"); } while (changesDone); final Node lastNode = flatNodes.get(flatNodes.size() - 1); @@ -1122,6 +1142,12 @@ public class BinaryDictInputOutput { } } + // The word cache here is a stopgap bandaid to help the catastrophic performance + // of this method. Since it performs direct, unbuffered random access to the file and + // may be called hundreds of thousands of times, the resulting performance is not + // reasonable without some kind of cache. Thus: + // TODO: perform buffered I/O here and in other places in the code. + private static TreeMap<Integer, String> wordCache = new TreeMap<Integer, String>(); /** * Finds, as a string, the word at the address passed as an argument. * @@ -1131,8 +1157,10 @@ public class BinaryDictInputOutput { * @return the word, as a string. * @throws IOException if the file can't be read. */ - private static String getWordAtAddress(RandomAccessFile source, long headerSize, + private static String getWordAtAddress(final RandomAccessFile source, final long headerSize, int address) throws IOException { + final String cachedString = wordCache.get(address); + if (null != cachedString) return cachedString; final long originalPointer = source.getFilePointer(); source.seek(headerSize); final int count = readCharGroupCount(source); @@ -1171,6 +1199,7 @@ public class BinaryDictInputOutput { } } source.seek(originalPointer); + wordCache.put(address, result); return result; } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java index a17371396..26a9415c4 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java @@ -171,7 +171,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, public boolean mMoreSuggestionsAvailable; - public final TextView mWordToSaveView; + private final TextView mWordToSaveView; private final TextView mLeftwardsArrowView; private final TextView mHintToSaveView; @@ -477,7 +477,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, } public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView, - int stripWidth, CharSequence hintText) { + int stripWidth, CharSequence hintText, OnClickListener listener) { final int width = stripWidth - mDividerWidth - mPadding * 2; final TextView wordView = mWordToSaveView; @@ -508,6 +508,18 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, stripView.addView(hintView); setLayoutWeight( hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); + + wordView.setOnClickListener(listener); + leftArrowView.setOnClickListener(listener); + hintView.setOnClickListener(listener); + } + + public CharSequence getAddToDictionaryWord() { + return (CharSequence)mWordToSaveView.getTag(); + } + + public boolean isAddToDictionaryShowing(View v) { + return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView; } private static void setLayoutWeight(View v, float weight, int height) { @@ -620,7 +632,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, } mParams = new SuggestionsViewParams(context, attrs, defStyle, mWords, mDividers, mInfos); - mParams.mWordToSaveView.setOnClickListener(this); mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer @@ -676,12 +687,12 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, public boolean isShowingAddToDictionaryHint() { return mSuggestionsStrip.getChildCount() > 0 - && mSuggestionsStrip.getChildAt(0) == mParams.mWordToSaveView; + && mParams.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0)); } public void showAddToDictionaryHint(CharSequence word, CharSequence hintText) { clear(); - mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText); + mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText, this); } public boolean dismissAddToDictionaryHint() { @@ -851,8 +862,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, @Override public void onClick(View view) { - if (view == mParams.mWordToSaveView) { - addToDictionary((CharSequence)view.getTag()); + if (mParams.isAddToDictionaryShowing(view)) { + addToDictionary(mParams.getAddToDictionaryWord()); clear(); return; } diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h index b8ac95250..d5d67c108 100644 --- a/native/jni/src/binary_format.h +++ b/native/jni/src/binary_format.h @@ -66,6 +66,7 @@ class BinaryFormat { const int length); static int getWordAtAddress(const uint8_t* const root, const int address, const int maxDepth, uint16_t* outWord); + static int getProbability(const int bigramListPosition, const int unigramFreq); // Flags for special processing // Those *must* match the flags in makedict (BinaryDictInputOutput#*_PROCESSING_FLAG) or @@ -517,6 +518,14 @@ inline int BinaryFormat::getWordAtAddress(const uint8_t* const root, const int a return 0; } +// This should probably return a probability in log space. +inline int BinaryFormat::getProbability(const int bigramListPosition, const int unigramFreq) { + // TODO: use the bigram list position to get the bigram probability. If the bigram + // is not found, use the unigram frequency. + // TODO: if the unigram frequency is used, compute the actual probability + return unigramFreq; +} + } // namespace latinime #endif // LATINIME_BINARY_FORMAT_H diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp index 087219ed4..376e9a10e 100644 --- a/native/jni/src/correction.cpp +++ b/native/jni/src/correction.cpp @@ -165,28 +165,28 @@ int Correction::getFreqForSplitMultipleWords(const int *freqArray, const int *wo wordCount, this, isSpaceProximity, word); } -int Correction::getFinalFreq(const int freq, unsigned short **word, int *wordLength) { - return getFinalFreqInternal(freq, word, wordLength, mInputLength); +int Correction::getFinalProbability(const int probability, unsigned short **word, int *wordLength) { + return getFinalProbabilityInternal(probability, word, wordLength, mInputLength); } -int Correction::getFinalFreqForSubQueue(const int freq, unsigned short **word, int *wordLength, - const int inputLength) { - return getFinalFreqInternal(freq, word, wordLength, inputLength); +int Correction::getFinalProbabilityForSubQueue(const int probability, unsigned short **word, + int *wordLength, const int inputLength) { + return getFinalProbabilityInternal(probability, word, wordLength, inputLength); } -int Correction::getFinalFreqInternal(const int freq, unsigned short **word, int *wordLength, - const int inputLength) { +int Correction::getFinalProbabilityInternal(const int probability, unsigned short **word, + int *wordLength, const int inputLength) { const int outputIndex = mTerminalOutputIndex; const int inputIndex = mTerminalInputIndex; *wordLength = outputIndex + 1; if (outputIndex < MIN_SUGGEST_DEPTH) { - return NOT_A_FREQUENCY; + return NOT_A_PROBABILITY; } *word = mWord; - int finalFreq = Correction::RankingAlgorithm::calculateFinalFreq( - inputIndex, outputIndex, freq, mEditDistanceTable, this, inputLength); - return finalFreq; + int finalProbability= Correction::RankingAlgorithm::calculateFinalProbability( + inputIndex, outputIndex, probability, mEditDistanceTable, this, inputLength); + return finalProbability; } bool Correction::initProcessState(const int outputIndex) { @@ -649,8 +649,8 @@ inline static bool isUpperCase(unsigned short c) { ////////////////////// /* static */ -int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const int outputIndex, - const int freq, int* editDistanceTable, const Correction* correction, +int Correction::RankingAlgorithm::calculateFinalProbability(const int inputIndex, + const int outputIndex, const int freq, int* editDistanceTable, const Correction* correction, const int inputLength) { const int excessivePos = correction->getExcessivePos(); const int typedLetterMultiplier = correction->TYPED_LETTER_MULTIPLIER; diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h index ee55c9604..1b4e4bf4e 100644 --- a/native/jni/src/correction.h +++ b/native/jni/src/correction.h @@ -132,9 +132,9 @@ class Correction { int getFreqForSplitMultipleWords( const int *freqArray, const int *wordLengthArray, const int wordCount, const bool isSpaceProximity, const unsigned short *word); - int getFinalFreq(const int freq, unsigned short **word, int* wordLength); - int getFinalFreqForSubQueue(const int freq, unsigned short **word, int* wordLength, - const int inputLength); + int getFinalProbability(const int probability, unsigned short **word, int* wordLength); + int getFinalProbabilityForSubQueue(const int probability, unsigned short **word, + int* wordLength, const int inputLength); CorrectionType processCharAndCalcState(const int32_t c, const bool isTerminal); @@ -156,8 +156,8 @@ class Correction { class RankingAlgorithm { public: - static int calculateFinalFreq(const int inputIndex, const int depth, - const int freq, int *editDistanceTable, const Correction* correction, + static int calculateFinalProbability(const int inputIndex, const int depth, + const int probability, int *editDistanceTable, const Correction* correction, const int inputLength); static int calcFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray, const int wordCount, const Correction* correction, const bool isSpaceProximity, @@ -182,8 +182,8 @@ class Correction { const int32_t c, const bool isTerminal, const bool inputIndexIncremented); inline CorrectionType processUnrelatedCorrectionType(); inline void addCharToCurrentWord(const int32_t c); - inline int getFinalFreqInternal(const int freq, unsigned short **word, int* wordLength, - const int inputLength); + inline int getFinalProbabilityInternal(const int probability, unsigned short **word, + int* wordLength, const int inputLength); const int TYPED_LETTER_MULTIPLIER; const int FULL_WORD_MULTIPLIER; diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index e882c3714..c99f8a8b2 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -172,7 +172,7 @@ static inline void prof_out(void) { #define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO -3 #define ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO -4 #define NOT_AN_INDEX -1 -#define NOT_A_FREQUENCY -1 +#define NOT_A_PROBABILITY -1 #define KEYCODE_SPACE ' ' diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp index 05c124b94..a3eda0061 100644 --- a/native/jni/src/unigram_dictionary.cpp +++ b/native/jni/src/unigram_dictionary.cpp @@ -349,7 +349,7 @@ void UnigramDictionary::getSuggestionCandidates(const bool useFullEditDistance, } } -inline void UnigramDictionary::onTerminal(const int freq, +inline void UnigramDictionary::onTerminal(const int probability, const TerminalAttributes& terminalAttributes, Correction *correction, WordsPriorityQueuePool *queuePool, const bool addToMasterQueue, const int currentWordIndex) { @@ -361,26 +361,28 @@ inline void UnigramDictionary::onTerminal(const int freq, if ((currentWordIndex == FIRST_WORD_INDEX) && addToMasterQueue) { WordsPriorityQueue *masterQueue = queuePool->getMasterQueue(); - const int finalFreq = correction->getFinalFreq(freq, &wordPointer, &wordLength); - if (finalFreq != NOT_A_FREQUENCY) { - addWord(wordPointer, wordLength, finalFreq, masterQueue); + const int finalProbability = + correction->getFinalProbability(probability, &wordPointer, &wordLength); + if (finalProbability != NOT_A_PROBABILITY) { + addWord(wordPointer, wordLength, finalProbability, masterQueue); - const int shortcutFreq = finalFreq > 0 ? finalFreq - 1 : 0; + const int shortcutProbability = finalProbability > 0 ? finalProbability - 1 : 0; // Please note that the shortcut candidates will be added to the master queue only. TerminalAttributes::ShortcutIterator iterator = terminalAttributes.getShortcutIterator(); while (iterator.hasNextShortcutTarget()) { // TODO: addWord only supports weak ordering, meaning we have no means // to control the order of the shortcuts relative to one another or to the word. - // We need to either modulate the frequency of each shortcut according - // to its own shortcut frequency or to make the queue + // We need to either modulate the probability of each shortcut according + // to its own shortcut probability or to make the queue // so that the insert order is protected inside the queue for words // with the same score. For the moment we use -1 to make sure the shortcut will // never be in front of the word. uint16_t shortcutTarget[MAX_WORD_LENGTH_INTERNAL]; const int shortcutTargetStringLength = iterator.getNextShortcutTarget( MAX_WORD_LENGTH_INTERNAL, shortcutTarget); - addWord(shortcutTarget, shortcutTargetStringLength, shortcutFreq, masterQueue); + addWord(shortcutTarget, shortcutTargetStringLength, shortcutProbability, + masterQueue); } } } @@ -393,9 +395,9 @@ inline void UnigramDictionary::onTerminal(const int freq, if (!subQueue) { return; } - const int finalFreq = correction->getFinalFreqForSubQueue(freq, &wordPointer, &wordLength, - inputIndex); - addWord(wordPointer, wordLength, finalFreq, subQueue); + const int finalProbability = correction->getFinalProbabilityForSubQueue( + probability, &wordPointer, &wordLength, inputIndex); + addWord(wordPointer, wordLength, finalProbability, subQueue); } } @@ -762,6 +764,8 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, correction->checkState(); } int pos = initialPos; + // TODO: get this as an argument + const int bigramListPosition = 0; // Flags contain the following information: // - Address type (MASK_GROUP_ADDRESS_TYPE) on two bits: @@ -834,11 +838,12 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, if (isTerminalNode) { // The frequency should be here, because we come here only if this is actually // a terminal node, and we are on its last char. - const int freq = BinaryFormat::readFrequencyWithoutMovingPointer(DICT_ROOT, pos); + const int unigramFreq = BinaryFormat::readFrequencyWithoutMovingPointer(DICT_ROOT, pos); const int childrenAddressPos = BinaryFormat::skipFrequency(flags, pos); const int attributesPos = BinaryFormat::skipChildrenPosition(flags, childrenAddressPos); TerminalAttributes terminalAttributes(DICT_ROOT, flags, attributesPos); - onTerminal(freq, terminalAttributes, correction, queuePool, needsToInvokeOnTerminal, + const int probability = BinaryFormat::getProbability(bigramListPosition, unigramFreq); + onTerminal(probability, terminalAttributes, correction, queuePool, needsToInvokeOnTerminal, currentWordIndex); // If there are more chars in this node, then this virtual node has children. diff --git a/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl b/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl index 5a193388a..8df94c1aa 100644 --- a/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl +++ b/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl @@ -25,7 +25,23 @@ import java.util.HashMap; /** * !!!!! DO NOT EDIT THIS FILE !!!!! - * This file is generated by tools/maketext. + * + * This file is generated by tools/maketext. The base template file is + * tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl + * + * This file must be updated when any text resources in keyboard layout files have been changed. + * These text resources are referred as "!text/<resource_name>" in keyboard XML definitions, + * and should be defined in + * tools/maketext/res/values-<locale>/donottranslate-more-keys.xml + * + * To update this file, please run the following commands. + * $ cd $ANDROID_BUILD_TOP + * $ mmm packages/inputmethods/LatinIME/tools/maketext + * $ maketext -java packages/inputmethods/LatinIME/java/src + * + * The updated source file will be generated to the following path (this file). + * packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/ + * KeyboardTextsSet.java */ public final class KeyboardTextsSet { // Language to texts map. |