From 4e3bd58b862afadd0325746b5c7ca9145b771762 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 15 Apr 2011 15:19:25 +0900 Subject: [PATCH 1/5] Allow use of assets for data in the dictionary content provider. This update is necessary to allow dictionary content providers to use assets, which are part of their apk, as data to pass to the keyboard. Using plain file descriptors doesn't allow for sections of files to be correctly used. Change-Id: Ia94c26d6387bce61c73d38f5c2821f20e50e54d4 --- .../inputmethod/latin/BinaryDictionaryFileDumper.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index d0464dd94..a78ff7e84 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import android.content.ContentResolver; import android.content.Context; +import android.content.res.AssetFileDescriptor; import android.net.Uri; import android.text.TextUtils; @@ -96,9 +97,9 @@ public class BinaryDictionaryFileDumper { // file. final ContentResolver resolver = context.getContentResolver(); final Uri dictionaryPackUri = getProviderUri(locale); - final InputStream stream = resolver.openInputStream(dictionaryPackUri); - if (null == stream) return null; - return copyFileTo(stream, getCacheFileNameForLocale(locale, context)); + final AssetFileDescriptor afd = resolver.openAssetFileDescriptor(dictionaryPackUri, "r"); + if (null == afd) return null; + return copyFileTo(afd.createInputStream(), getCacheFileNameForLocale(locale, context)); } /** @@ -128,6 +129,8 @@ public class BinaryDictionaryFileDumper { /** * Copies the data in an input stream to a target file, creating the file if necessary and * overwriting it if it already exists. + * @param input the stream to be copied. + * @param outputFileName the name of a file to copy the data to. It is created if necessary. */ private static String copyFileTo(final InputStream input, final String outputFileName) throws FileNotFoundException, IOException { From 73544aded738cbb8ff022c239a14929a0ef68a8c Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Fri, 15 Apr 2011 14:46:55 -0700 Subject: [PATCH 2/5] Import revised translations. Change-Id: Icdf10a328353d201b5751ac7f21f2fb7a64b3daa --- java/res/values-el/strings.xml | 2 +- java/res/values-nl/strings.xml | 2 +- java/res/values-ro/strings.xml | 2 +- java/res/values-tl/strings.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 70f1d48c5..305bb4fe2 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -48,7 +48,7 @@ "Προτάσεις bigram" "Χρήση προηγούμενης λέξης για τη βελτίωση πρότασης" "%s : Αποθηκεύτηκε" - "Μετάβαση" + "Μετ." "Επόμενο" "Τέλος" "Αποστολή" diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index e52ad2e2a..0efb45b7b 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -48,7 +48,7 @@ "Digram-suggesties" "Vorig woord gebruiken om suggestie te verbeteren" "%s: opgeslagen" - "Beginnen" + "Start" "Volgende" "Gereed" "Verzenden" diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index a0b5df381..c9639a807 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -48,7 +48,7 @@ "Sugestii pentru cuvinte de două litere" "Utilizaţi cuvântul anterior pentru a îmbunătăţi sugestia" "%s: salvat" - "Accesaţi" + "OK" "Înainte" "Terminat" "Trimiteţi" diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index ce9abf8bd..5906b5874 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -48,7 +48,7 @@ "Mga Suhestiyon na Bigram" "Gamitin ang nakaraang salita upang pahusayin ang suhestiyon" "%s : Na-save" - "Pumunta" + "Punta" "Susunod" "Tapos na" "Ipadala" From dccb31ddee5f437eb017403e75b018262a536cb1 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Mon, 18 Apr 2011 11:34:44 +0900 Subject: [PATCH 3/5] Fix issues with single-char word. Some refactorings as well. Change-Id: If20a15324d7704361dd61e0e431b665552567ea3 --- .../tools/dict/MakeBinaryDictionary.java | 230 +++++++++--------- 1 file changed, 116 insertions(+), 114 deletions(-) diff --git a/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java index 51e203849..4a285ff07 100644 --- a/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java +++ b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java @@ -41,18 +41,17 @@ import javax.xml.parsers.SAXParserFactory; * in the data. There is no need to increase the version when only the words in the data changes. */ public class MakeBinaryDictionary { - private static final int VERSION_NUM = 200; - public static final int ALPHA_SIZE = 256; - - public static final String TAG_WORD = "w"; - public static final String ATTR_FREQ = "f"; + private static final String TAG_WORD = "w"; + private static final String ATTR_FREQ = "f"; private static final int FLAG_ADDRESS_MASK = 0x400000; private static final int FLAG_TERMINAL_MASK = 0x800000; private static final int ADDRESS_MASK = 0x3FFFFF; + private static final int INITIAL_STRING_BUILDER_CAPACITY = 48; + /** * Unit for this variable is in bytes * If destination file name is main.dict and file limit causes dictionary to be separated into @@ -61,15 +60,15 @@ public class MakeBinaryDictionary { private static int sOutputFileSize; private static boolean sSplitOutput; - public static final CharNode EMPTY_NODE = new CharNode(); + private static final CharNode EMPTY_NODE = new CharNode(); - List roots; - Map mDictionary; - int mWordCount; + private List mRoots; + private Map mDictionary; + private int mWordCount; - BigramDictionary bigramDict; + private BigramDictionary mBigramDict; - static class CharNode { + private static class CharNode { char data; int freq; boolean terminal; @@ -81,7 +80,7 @@ public class MakeBinaryDictionary { } } - public static void usage() { + private static void usage() { System.err.println("Usage: makedict -s [-b ] " + "-d [--size filesize]"); System.exit(-1); @@ -118,36 +117,37 @@ public class MakeBinaryDictionary { } } - public MakeBinaryDictionary(String srcFilename, String bigramSrcFilename, String destFilename){ + private MakeBinaryDictionary(String srcFilename, String bigramSrcFilename, + String destFilename) { System.out.println("Generating dictionary version " + VERSION_NUM); - bigramDict = new BigramDictionary(bigramSrcFilename, (bigramSrcFilename != null)); + mBigramDict = new BigramDictionary(bigramSrcFilename, (bigramSrcFilename != null)); populateDictionary(srcFilename); writeToDict(destFilename); // Enable the code below to verify that the generated tree is traversable // and bigram data is stored correctly. if (false) { - bigramDict.reverseLookupAll(mDictionary, dict); + mBigramDict.reverseLookupAll(mDictionary, mDict); traverseDict(2, new char[32], 0); } } private void populateDictionary(String filename) { - roots = new ArrayList(); + mRoots = new ArrayList(); mDictionary = new HashMap(); try { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(new File(filename), new DefaultHandler() { boolean inWord; int freq; - StringBuilder wordBuilder = new StringBuilder(48); + StringBuilder wordBuilder = new StringBuilder(INITIAL_STRING_BUILDER_CAPACITY); @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { - if (qName.equals("w")) { + if (qName.equals(TAG_WORD)) { inWord = true; - freq = Integer.parseInt(attributes.getValue(0)); + freq = Integer.parseInt(attributes.getValue(ATTR_FREQ)); wordBuilder.setLength(0); } } @@ -162,7 +162,7 @@ public class MakeBinaryDictionary { @Override public void endElement(String uri, String localName, String qName) { - if (qName.equals("w")) { + if (qName.equals(TAG_WORD)) { if (wordBuilder.length() >= 1) { addWordTop(wordBuilder.toString(), freq); mWordCount++; @@ -178,7 +178,7 @@ public class MakeBinaryDictionary { System.out.println("Nodes = " + CharNode.sNodes); } - private int indexOf(List children, char c) { + private static int indexOf(List children, char c) { if (children == null) { return -1; } @@ -190,27 +190,30 @@ public class MakeBinaryDictionary { return -1; } - private void addWordTop(String word, int occur) { - if (occur > 255) occur = 255; + private void addWordTop(String word, int freq) { + if (freq < 0) { + freq = 0; + } else if (freq > 255) { + freq = 255; + } char firstChar = word.charAt(0); - int index = indexOf(roots, firstChar); + int index = indexOf(mRoots, firstChar); if (index == -1) { CharNode newNode = new CharNode(); newNode.data = firstChar; - newNode.freq = occur; - index = roots.size(); - roots.add(newNode); - } else { - roots.get(index).freq += occur; + index = mRoots.size(); + mRoots.add(newNode); } + final CharNode node = mRoots.get(index); if (word.length() > 1) { - addWordRec(roots.get(index), word, 1, occur); + addWordRec(node, word, 1, freq); } else { - roots.get(index).terminal = true; + node.terminal = true; + node.freq = freq; } } - private void addWordRec(CharNode parent, String word, int charAt, int occur) { + private void addWordRec(CharNode parent, String word, int charAt, int freq) { CharNode child = null; char data = word.charAt(charAt); if (parent.children == null) { @@ -229,89 +232,89 @@ public class MakeBinaryDictionary { parent.children.add(child); } child.data = data; - if (child.freq == 0) child.freq = occur; if (word.length() > charAt + 1) { - addWordRec(child, word, charAt + 1, occur); + addWordRec(child, word, charAt + 1, freq); } else { child.terminal = true; - child.freq = occur; + child.freq = freq; } } - byte[] dict; - int dictSize; - static final int CHAR_WIDTH = 8; - static final int FLAGS_WIDTH = 1; // Terminal flag (word end) - static final int ADDR_WIDTH = 23; // Offset to children - static final int FREQ_WIDTH_BYTES = 1; - static final int COUNT_WIDTH_BYTES = 1; + private byte[] mDict; + private int mDictSize; + private static final int CHAR_WIDTH = 8; + private static final int FLAGS_WIDTH = 1; // Terminal flag (word end) + private static final int ADDR_WIDTH = 23; // Offset to children + private static final int FREQ_WIDTH_BYTES = 1; + private static final int COUNT_WIDTH_BYTES = 1; private void addCount(int count) { - dict[dictSize++] = (byte) (0xFF & count); + mDict[mDictSize++] = (byte) (0xFF & count); } private void addNode(CharNode node, String word1) { - if (node.terminal) { // store address of each word1 - mDictionary.put(word1, dictSize); + if (node.terminal) { // store address of each word1 for bigram dic generation + mDictionary.put(word1, mDictSize); } + int charData = 0xFFFF & node.data; if (charData > 254) { - dict[dictSize++] = (byte) 255; - dict[dictSize++] = (byte) ((node.data >> 8) & 0xFF); - dict[dictSize++] = (byte) (node.data & 0xFF); + mDict[mDictSize++] = (byte) 255; + mDict[mDictSize++] = (byte) ((node.data >> 8) & 0xFF); + mDict[mDictSize++] = (byte) (node.data & 0xFF); } else { - dict[dictSize++] = (byte) (0xFF & node.data); + mDict[mDictSize++] = (byte) (0xFF & node.data); } if (node.children != null) { - dictSize += 3; // Space for children address + mDictSize += 3; // Space for children address } else { - dictSize += 1; // Space for just the terminal/address flags + mDictSize += 1; // Space for just the terminal/address flags } if ((0xFFFFFF & node.freq) > 255) { node.freq = 255; } if (node.terminal) { byte freq = (byte) (0xFF & node.freq); - dict[dictSize++] = freq; + mDict[mDictSize++] = freq; // bigram - if (bigramDict.mBi.containsKey(word1)) { - int count = bigramDict.mBi.get(word1).count; - bigramDict.mBigramToFill.add(word1); - bigramDict.mBigramToFillAddress.add(dictSize); - dictSize += (4 * count); + if (mBigramDict.mBi.containsKey(word1)) { + int count = mBigramDict.mBi.get(word1).count; + mBigramDict.mBigramToFill.add(word1); + mBigramDict.mBigramToFillAddress.add(mDictSize); + mDictSize += (4 * count); } else { - dict[dictSize++] = (byte) (0x00); + mDict[mDictSize++] = (byte) (0x00); } } } - int nullChildrenCount = 0; - int notTerminalCount = 0; + private int mNullChildrenCount = 0; + private int mNotTerminalCount = 0; private void updateNodeAddress(int nodeAddress, CharNode node, int childrenAddress) { - if ((dict[nodeAddress] & 0xFF) == 0xFF) { // 3 byte character + if ((mDict[nodeAddress] & 0xFF) == 0xFF) { // 3 byte character nodeAddress += 2; } childrenAddress = ADDRESS_MASK & childrenAddress; if (childrenAddress == 0) { - nullChildrenCount++; + mNullChildrenCount++; } else { childrenAddress |= FLAG_ADDRESS_MASK; } if (node.terminal) { childrenAddress |= FLAG_TERMINAL_MASK; } else { - notTerminalCount++; + mNotTerminalCount++; } - dict[nodeAddress + 1] = (byte) (childrenAddress >> 16); + mDict[nodeAddress + 1] = (byte) (childrenAddress >> 16); if ((childrenAddress & FLAG_ADDRESS_MASK) != 0) { - dict[nodeAddress + 2] = (byte) ((childrenAddress & 0xFF00) >> 8); - dict[nodeAddress + 3] = (byte) ((childrenAddress & 0xFF)); + mDict[nodeAddress + 2] = (byte) ((childrenAddress & 0xFF00) >> 8); + mDict[nodeAddress + 3] = (byte) ((childrenAddress & 0xFF)); } } - void writeWordsRec(List children, StringBuilder word) { + private void writeWordsRec(List children, StringBuilder word) { if (children == null || children.size() == 0) { return; } @@ -319,60 +322,59 @@ public class MakeBinaryDictionary { addCount(childCount); int[] childrenAddresses = new int[childCount]; for (int j = 0; j < childCount; j++) { - CharNode node = children.get(j); - childrenAddresses[j] = dictSize; - word.append(children.get(j).data); - addNode(node, word.toString()); - word.deleteCharAt(word.length()-1); + CharNode child = children.get(j); + childrenAddresses[j] = mDictSize; + word.append(child.data); + addNode(child, word.toString()); + word.setLength(word.length() - 1); } for (int j = 0; j < childCount; j++) { - CharNode node = children.get(j); + CharNode child = children.get(j); int nodeAddress = childrenAddresses[j]; - int cacheDictSize = dictSize; - word.append(children.get(j).data); - writeWordsRec(node.children, word); - word.deleteCharAt(word.length()-1); - updateNodeAddress(nodeAddress, node, node.children != null - ? cacheDictSize : 0); + int cacheDictSize = mDictSize; + word.append(child.data); + writeWordsRec(child.children, word); + word.setLength(word.length() - 1); + updateNodeAddress(nodeAddress, child, child.children != null ? cacheDictSize : 0); } } - void writeToDict(String dictFilename) { + private void writeToDict(String dictFilename) { // 4MB max, 22-bit offsets - dict = new byte[4 * 1024 * 1024]; // 4MB upper limit. Actual is probably - // < 1MB in most cases, as there is a limit in the - // resource size in apks. - dictSize = 0; + mDict = new byte[4 * 1024 * 1024]; // 4MB upper limit. Actual is probably + // < 1MB in most cases, as there is a limit in the + // resource size in apks. + mDictSize = 0; - dict[dictSize++] = (byte) (0xFF & VERSION_NUM); // version info - dict[dictSize++] = (byte) (0xFF & (bigramDict.mHasBigram ? 1 : 0)); + mDict[mDictSize++] = (byte) (0xFF & VERSION_NUM); // version info + mDict[mDictSize++] = (byte) (0xFF & (mBigramDict.mHasBigram ? 1 : 0)); - StringBuilder word = new StringBuilder(48); - writeWordsRec(roots, word); - dict = bigramDict.writeBigrams(dict, mDictionary); - System.out.println("Dict Size = " + dictSize); + final StringBuilder word = new StringBuilder(INITIAL_STRING_BUILDER_CAPACITY); + writeWordsRec(mRoots, word); + mDict = mBigramDict.writeBigrams(mDict, mDictionary); + System.out.println("Dict Size = " + mDictSize); if (!sSplitOutput) { - sOutputFileSize = dictSize; + sOutputFileSize = mDictSize; } try { int currentLoc = 0; int i = 0; int extension = dictFilename.indexOf(".dict"); String filename = dictFilename.substring(0, extension); - while (dictSize > 0) { + while (mDictSize > 0) { FileOutputStream fos; if (sSplitOutput) { fos = new FileOutputStream(filename + i + ".dict"); } else { fos = new FileOutputStream(filename + ".dict"); } - if (dictSize > sOutputFileSize) { - fos.write(dict, currentLoc, sOutputFileSize); - dictSize -= sOutputFileSize; + if (mDictSize > sOutputFileSize) { + fos.write(mDict, currentLoc, sOutputFileSize); + mDictSize -= sOutputFileSize; currentLoc += sOutputFileSize; } else { - fos.write(dict, currentLoc, dictSize); - dictSize = 0; + fos.write(mDict, currentLoc, mDictSize); + mDictSize = 0; } fos.close(); i++; @@ -382,36 +384,36 @@ public class MakeBinaryDictionary { } } - void traverseDict(int pos, char[] word, int depth) { - int count = dict[pos++] & 0xFF; + private void traverseDict(int pos, char[] word, int depth) { + int count = mDict[pos++] & 0xFF; for (int i = 0; i < count; i++) { - char c = (char) (dict[pos++] & 0xFF); + char c = (char) (mDict[pos++] & 0xFF); if (c == 0xFF) { // two byte character - c = (char) (((dict[pos] & 0xFF) << 8) | (dict[pos+1] & 0xFF)); + c = (char) (((mDict[pos] & 0xFF) << 8) | (mDict[pos+1] & 0xFF)); pos += 2; } word[depth] = c; - boolean terminal = getFirstBitOfByte(pos, dict); + boolean terminal = getFirstBitOfByte(pos, mDict); int address = 0; - if ((dict[pos] & (FLAG_ADDRESS_MASK >> 16)) > 0) { // address check - address = get22BitAddress(pos, dict); + if ((mDict[pos] & (FLAG_ADDRESS_MASK >> 16)) > 0) { // address check + address = get22BitAddress(pos, mDict); pos += 3; } else { pos += 1; } if (terminal) { - showWord(word, depth + 1, dict[pos] & 0xFF); + showWord(word, depth + 1, mDict[pos] & 0xFF); pos++; - int bigramExist = (dict[pos] & bigramDict.FLAG_BIGRAM_READ); + int bigramExist = (mDict[pos] & mBigramDict.FLAG_BIGRAM_READ); if (bigramExist > 0) { int nextBigramExist = 1; while (nextBigramExist > 0) { - int bigramAddress = get22BitAddress(pos, dict); + int bigramAddress = get22BitAddress(pos, mDict); pos += 3; - int frequency = (bigramDict.FLAG_BIGRAM_FREQ & dict[pos]); - bigramDict.searchForTerminalNode(bigramAddress, frequency, dict); - nextBigramExist = (dict[pos++] & bigramDict.FLAG_BIGRAM_CONTINUED); + int frequency = (mBigramDict.FLAG_BIGRAM_FREQ & mDict[pos]); + mBigramDict.searchForTerminalNode(bigramAddress, frequency, mDict); + nextBigramExist = (mDict[pos++] & mBigramDict.FLAG_BIGRAM_CONTINUED); } } else { pos++; @@ -423,21 +425,21 @@ public class MakeBinaryDictionary { } } - void showWord(char[] word, int size, int freq) { + private static void showWord(char[] word, int size, int freq) { System.out.print(new String(word, 0, size) + " " + freq + "\n"); } - static int get22BitAddress(int pos, byte[] dict) { + /* package */ static int get22BitAddress(int pos, byte[] dict) { return ((dict[pos + 0] & 0x3F) << 16) | ((dict[pos + 1] & 0xFF) << 8) | ((dict[pos + 2] & 0xFF)); } - static boolean getFirstBitOfByte(int pos, byte[] dict) { + /* package */ static boolean getFirstBitOfByte(int pos, byte[] dict) { return (dict[pos] & 0x80) > 0; } - static boolean getSecondBitOfByte(int pos, byte[] dict) { + /* package */ static boolean getSecondBitOfByte(int pos, byte[] dict) { return (dict[pos] & 0x40) > 0; } } From a4374d2eb70dad908b1d1b8b58f0c9d3d337fef4 Mon Sep 17 00:00:00 2001 From: satok Date: Mon, 18 Apr 2011 11:40:22 +0900 Subject: [PATCH 4/5] Promote the correction of words with a missing space character Change-Id: I37ba618b54f7115163a3e9c6c555485e7024dc92 --- native/src/defines.h | 2 +- native/src/unigram_dictionary.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/native/src/defines.h b/native/src/defines.h index bdab19ff7..a5ed6827b 100644 --- a/native/src/defines.h +++ b/native/src/defines.h @@ -140,7 +140,7 @@ static void prof_out(void) { // The following "rate"s are used as a multiplier before dividing by 100, so they are in percent. #define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 80 #define WORDS_WITH_MISSING_CHARACTER_DEMOTION_START_POS_10X 12 -#define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 80 +#define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 75 #define WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE 75 #define WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE 75 #define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 60 diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index 89a1c9ea6..8e82f1474 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -448,8 +448,14 @@ bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength, word[i] = mWord[i - firstWordLength - 1]; } - int pairFreq = ((firstFreq + secondFreq) / 2); + // Promote pairFreq with multiplying by 2, because the word length is the same as the typed + // length. + int pairFreq = firstFreq + secondFreq; for (int i = 0; i < inputLength; ++i) pairFreq *= TYPED_LETTER_MULTIPLIER; + if (DEBUG_DICT) { + LOGI("Missing space: %d, %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength, + TYPED_LETTER_MULTIPLIER); + } multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &pairFreq); addWord(word, newWordLength, pairFreq); return true; From bc3dba451a7af85eab600968fbafda3040b7ced4 Mon Sep 17 00:00:00 2001 From: satok Date: Mon, 18 Apr 2011 16:06:31 +0900 Subject: [PATCH 5/5] A fix for handling dummy voice subtypes Change-Id: I75d4d1625e0925d01ae84c9577e15087d83e4191 --- .../compat/InputMethodManagerCompatWrapper.java | 15 ++++++++++----- .../compat/InputMethodServiceCompatWrapper.java | 2 +- .../inputmethod/latin/SubtypeSwitcher.java | 6 +++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 2b7e25591..0c2a58ea9 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -67,7 +67,6 @@ public class InputMethodManagerCompatWrapper { // For the compatibility, IMM will create dummy subtypes if subtypes are not found. // This is required to be false if the current behavior is broken. For now, it's ok to be true. - private static final boolean ALLOW_DUMMY_SUBTYPE = true; private static final boolean HAS_VOICE_FUNCTION = true; private static final String VOICE_MODE = "voice"; private static final String KEYBOARD_MODE = "keyboard"; @@ -119,11 +118,13 @@ public class InputMethodManagerCompatWrapper { Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList, (imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes); if (retval == null || !(retval instanceof List) || ((List)retval).isEmpty()) { - if (!ALLOW_DUMMY_SUBTYPE) { + if (InputMethodServiceCompatWrapper. + CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { // Returns an empty list return Collections.emptyList(); } // Creates dummy subtypes + @SuppressWarnings("unused") List subtypeList = new ArrayList(); InputMethodSubtypeCompatWrapper keyboardSubtype = getLastResortSubtype(KEYBOARD_MODE); @@ -159,11 +160,13 @@ public class InputMethodManagerCompatWrapper { getShortcutInputMethodsAndSubtypes() { Object retval = CompatUtils.invoke(mImm, null, METHOD_getShortcutInputMethodsAndSubtypes); if (retval == null || !(retval instanceof Map) || ((Map)retval).isEmpty()) { - if (!ALLOW_DUMMY_SUBTYPE) { + if (InputMethodServiceCompatWrapper. + CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { // Returns an empty map return Collections.emptyMap(); } // Creates dummy subtypes + @SuppressWarnings("unused") InputMethodInfoCompatWrapper imi = getLatinImeInputMethodInfo(); InputMethodSubtypeCompatWrapper voiceSubtype = getLastResortSubtype(VOICE_MODE); if (imi != null && voiceSubtype != null) { @@ -196,8 +199,10 @@ public class InputMethodManagerCompatWrapper { public void setInputMethodAndSubtype( IBinder token, String id, InputMethodSubtypeCompatWrapper subtype) { - CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype, - token, id, subtype.getOriginalObject()); + if (subtype != null && subtype.hasOriginalObject()) { + CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype, + token, id, subtype.getOriginalObject()); + } } public boolean switchToLastInputMethod(IBinder token) { diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java index 399dcf2dd..d6afd06c5 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java @@ -28,7 +28,7 @@ public class InputMethodServiceCompatWrapper extends InputMethodService { // For the API level 11 or later, LatinIME should override onCurrentInputMethodSubtypeChanged(). // For the API level 10 or previous, we handle the "subtype changed" events by ourselves // without having support from framework -- onCurrentInputMethodSubtypeChanged(). - private static final boolean CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED = true; + public static final boolean CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED = true; private InputMethodManagerCompatWrapper mImm; diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 2cdc4d2cd..632195533 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -382,12 +382,16 @@ public class SubtypeSwitcher { return false; if (mShortcutSubtype == null) return true; + // For compatibility, if the shortcut subtype is dummy, we assume the shortcut IME + // (built-in voice dummy subtype) is available. + if (!mShortcutSubtype.hasOriginalObject()) return true; final boolean allowsImplicitlySelectedSubtypes = true; for (final InputMethodSubtypeCompatWrapper enabledSubtype : mImm.getEnabledInputMethodSubtypeList( mShortcutInputMethodInfo, allowsImplicitlySelectedSubtypes)) { - if (enabledSubtype.equals(mShortcutSubtype)) + if (enabledSubtype.equals(mShortcutSubtype)) { return true; + } } return false; }