diff options
Diffstat (limited to 'java/src')
7 files changed, 101 insertions, 82 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index fd9edec70..5e68c7067 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -301,8 +301,10 @@ public final class KeyboardLayoutSet { final int xmlId = mResources.getIdentifier(keyboardLayoutSetName, "xml", packageName); try { parseKeyboardLayoutSet(mResources, xmlId); - } catch (Exception e) { - throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName); + } catch (final IOException e) { + throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName, e); + } catch (final XmlPullParserException e) { + throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName, e); } return new KeyboardLayoutSet(mContext, mParams); } @@ -311,14 +313,14 @@ public final class KeyboardLayoutSet { throws XmlPullParserException, IOException { final XmlResourceParser parser = res.getXml(resId); try { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final int event = parser.next(); if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_KEYBOARD_SET.equals(tag)) { parseKeyboardLayoutSetContent(parser); } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); + throw new XmlParseUtils.IllegalStartTag(parser, tag, TAG_KEYBOARD_SET); } } } @@ -329,21 +331,21 @@ public final class KeyboardLayoutSet { private void parseKeyboardLayoutSetContent(final XmlPullParser parser) throws XmlPullParserException, IOException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final int event = parser.next(); if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_ELEMENT.equals(tag)) { parseKeyboardLayoutSetElement(parser); } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); + throw new XmlParseUtils.IllegalStartTag(parser, tag, TAG_KEYBOARD_SET); } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); if (TAG_KEYBOARD_SET.equals(tag)) { break; } else { - throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEYBOARD_SET); + throw new XmlParseUtils.IllegalEndTag(parser, tag, TAG_KEYBOARD_SET); } } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index 8ae1b8881..be178f516 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -164,10 +164,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> { parseKeyboard(parser); } catch (XmlPullParserException e) { Log.w(BUILDER_TAG, "keyboard XML parse error", e); - throw new IllegalArgumentException(e); + throw new IllegalArgumentException(e.getMessage(), e); } catch (IOException e) { Log.w(BUILDER_TAG, "keyboard XML parse error", e); - throw new RuntimeException(e); + throw new RuntimeException(e.getMessage(), e); } finally { parser.close(); } @@ -210,8 +210,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> { private void parseKeyboard(final XmlPullParser parser) throws XmlPullParserException, IOException { if (DEBUG) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId); - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final int event = parser.next(); if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_KEYBOARD.equals(tag)) { @@ -220,7 +220,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { parseKeyboardContent(parser, false); break; } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD); + throw new XmlParseUtils.IllegalStartTag(parser, tag, TAG_KEYBOARD); } } } @@ -303,8 +303,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> { private void parseKeyboardContent(final XmlPullParser parser, final boolean skip) throws XmlPullParserException, IOException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final int event = parser.next(); if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_ROW.equals(tag)) { @@ -321,7 +321,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { } else if (TAG_KEY_STYLE.equals(tag)) { parseKeyStyle(parser, skip); } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW); + throw new XmlParseUtils.IllegalStartTag(parser, tag, TAG_ROW); } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); @@ -333,7 +333,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { || TAG_MERGE.equals(tag)) { break; } else { - throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW); + throw new XmlParseUtils.IllegalEndTag(parser, tag, TAG_ROW); } } } @@ -345,10 +345,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> { R.styleable.Keyboard); try { if (a.hasValue(R.styleable.Keyboard_horizontalGap)) { - throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap"); + throw new XmlParseUtils.IllegalAttribute(parser, TAG_ROW, "horizontalGap"); } if (a.hasValue(R.styleable.Keyboard_verticalGap)) { - throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap"); + throw new XmlParseUtils.IllegalAttribute(parser, TAG_ROW, "verticalGap"); } return new KeyboardRow(mResources, mParams, parser, mCurrentY); } finally { @@ -358,8 +358,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> { private void parseRowContent(final XmlPullParser parser, final KeyboardRow row, final boolean skip) throws XmlPullParserException, IOException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final int event = parser.next(); if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_KEY.equals(tag)) { @@ -373,7 +373,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { } else if (TAG_KEY_STYLE.equals(tag)) { parseKeyStyle(parser, skip); } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); + throw new XmlParseUtils.IllegalStartTag(parser, tag, TAG_ROW); } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); @@ -387,7 +387,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { || TAG_MERGE.equals(tag)) { break; } else { - throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); + throw new XmlParseUtils.IllegalEndTag(parser, tag, TAG_ROW); } } } @@ -506,8 +506,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> { private void parseMerge(final XmlPullParser parser, final KeyboardRow row, final boolean skip) throws XmlPullParserException, IOException { if (DEBUG) startTag("<%s>", TAG_MERGE); - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final int event = parser.next(); if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_MERGE.equals(tag)) { @@ -539,8 +539,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> { final boolean skip) throws XmlPullParserException, IOException { if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId); boolean selected = false; - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final int event = parser.next(); if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_CASE.equals(tag)) { @@ -548,7 +548,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { } else if (TAG_DEFAULT.equals(tag)) { selected |= parseDefault(parser, row, selected ? true : skip); } else { - throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); + throw new XmlParseUtils.IllegalStartTag(parser, tag, TAG_SWITCH); } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); @@ -556,7 +556,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { if (DEBUG) endTag("</%s>", TAG_SWITCH); break; } else { - throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); + throw new XmlParseUtils.IllegalEndTag(parser, tag, TAG_SWITCH); } } } diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index ae2ee577f..fd81d13ca 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import android.content.Context; import android.text.TextUtils; +import android.util.Log; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; @@ -31,6 +32,7 @@ import java.util.LinkedList; * be searched for suggestions and valid words. */ public class ExpandableDictionary extends Dictionary { + private static final String TAG = ExpandableDictionary.class.getSimpleName(); /** * The weight to give to a word if it's length is the same as the number of typed characters. */ @@ -551,8 +553,13 @@ public class ExpandableDictionary extends Dictionary { // word. We do want however to return the correct case for the right hand side. // So we want to squash the case of the left hand side, and preserve that of the right // hand side word. - Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); - Node secondWord = searchWord(mRoots, word2, 0, null); + final String word1Lower = word1.toLowerCase(); + if (TextUtils.isEmpty(word1Lower) || TextUtils.isEmpty(word2)) { + Log.e(TAG, "Invalid bigram pair: " + word1 + ", " + word1Lower + ", " + word2); + return frequency; + } + final Node firstWord = searchWord(mRoots, word1Lower, 0, null); + final Node secondWord = searchWord(mRoots, word2, 0, null); LinkedList<NextWord> bigrams = firstWord.mNGrams; if (bigrams == null || bigrams.size() == 0) { firstWord.mNGrams = CollectionUtils.newLinkedList(); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index ea7ee6d5b..92b68dcd7 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -156,7 +156,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private PositionalInfoForUserDictPendingAddition mPositionalInfoForUserDictPendingAddition = null; private final WordComposer mWordComposer = new WordComposer(); - private RichInputConnection mConnection = new RichInputConnection(this); + private final RichInputConnection mConnection = new RichInputConnection(this); // Keep track of the last selection range to decide if we need to show word alternatives private static final int NOT_A_CURSOR_POSITION = -1; @@ -803,10 +803,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @Override public void onWindowHidden() { - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_onWindowHidden(mLastSelectionStart, mLastSelectionEnd, - getCurrentInputConnection()); - } super.onWindowHidden(); final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); if (mainKeyboardView != null) { @@ -834,8 +830,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // Remove pending messages related to update suggestions mHandler.cancelUpdateSuggestionStrip(); resetComposingState(true /* alsoResetLastComposedWord */); + // Notify ResearchLogger if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.getInstance().latinIME_onFinishInputViewInternal(); + ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput, mLastSelectionStart, + mLastSelectionEnd, getCurrentInputConnection()); } } @@ -2297,25 +2295,27 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // expect to receive non-words. if (!mSettings.getCurrent().mCorrectionEnabled) return null; + final Suggest suggest = mSuggest; final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; - if (userHistoryDictionary != null) { - final String prevWord - = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2); - final String secondWord; - if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { - secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); - } else { - secondWord = suggestion; - } - // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". - // We don't add words with 0-frequency (assuming they would be profanity etc.). - final int maxFreq = AutoCorrection.getMaxFrequency( - mSuggest.getUnigramDictionaries(), suggestion); - if (maxFreq == 0) return null; - userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0); - return prevWord; - } - return null; + if (suggest == null || userHistoryDictionary == null) { + // Avoid concurrent issue + return null; + } + final String prevWord + = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2); + final String secondWord; + if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { + secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); + } else { + secondWord = suggestion; + } + // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". + // We don't add words with 0-frequency (assuming they would be profanity etc.). + final int maxFreq = AutoCorrection.getMaxFrequency( + suggest.getUnigramDictionaries(), suggestion); + if (maxFreq == 0) return null; + userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0); + return prevWord; } /** diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java index 62f2a9750..10931555e 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java @@ -207,7 +207,12 @@ public final class UserHistoryDictIOUtils { final ArrayList<PendingAttribute> attrList = bigrams.get(entry.getKey()); if (attrList != null) { for (final PendingAttribute attr : attrList) { - to.setBigram(word1, unigrams.get(attr.mAddress), + final String word2 = unigrams.get(attr.mAddress); + if (word1 == null || word2 == null) { + Log.e(TAG, "Invalid bigram pair detected: " + word1 + ", " + word2); + continue; + } + to.setBigram(word1, word2, BinaryDictInputOutput.reconstructBigramFrequency(unigramFrequency, attr.mFrequency)); } diff --git a/java/src/com/android/inputmethod/latin/XmlParseUtils.java b/java/src/com/android/inputmethod/latin/XmlParseUtils.java index f01d4c5e6..48e5ed30a 100644 --- a/java/src/com/android/inputmethod/latin/XmlParseUtils.java +++ b/java/src/com/android/inputmethod/latin/XmlParseUtils.java @@ -30,50 +30,53 @@ public final class XmlParseUtils { @SuppressWarnings("serial") public static class ParseException extends XmlPullParserException { - public ParseException(String msg, XmlPullParser parser) { + public ParseException(final String msg, final XmlPullParser parser) { super(msg + " at " + parser.getPositionDescription()); } } @SuppressWarnings("serial") public static final class IllegalStartTag extends ParseException { - public IllegalStartTag(XmlPullParser parser, String parent) { - super("Illegal start tag " + parser.getName() + " in " + parent, parser); + public IllegalStartTag(final XmlPullParser parser, final String tag, final String parent) { + super("Illegal start tag " + tag + " in " + parent, parser); } } @SuppressWarnings("serial") public static final class IllegalEndTag extends ParseException { - public IllegalEndTag(XmlPullParser parser, String parent) { - super("Illegal end tag " + parser.getName() + " in " + parent, parser); + public IllegalEndTag(final XmlPullParser parser, final String tag, final String parent) { + super("Illegal end tag " + tag + " in " + parent, parser); } } @SuppressWarnings("serial") public static final class IllegalAttribute extends ParseException { - public IllegalAttribute(XmlPullParser parser, String attribute) { - super("Tag " + parser.getName() + " has illegal attribute " + attribute, parser); + public IllegalAttribute(final XmlPullParser parser, final String tag, + final String attribute) { + super("Tag " + tag + " has illegal attribute " + attribute, parser); } } @SuppressWarnings("serial") public static final class NonEmptyTag extends ParseException{ - public NonEmptyTag(String tag, XmlPullParser parser) { + public NonEmptyTag(final XmlPullParser parser, final String tag) { super(tag + " must be empty tag", parser); } } - public static void checkEndTag(String tag, XmlPullParser parser) + public static void checkEndTag(final String tag, final XmlPullParser parser) throws XmlPullParserException, IOException { if (parser.next() == XmlPullParser.END_TAG && tag.equals(parser.getName())) return; - throw new NonEmptyTag(tag, parser); + throw new NonEmptyTag(parser, tag); } - public static void checkAttributeExists(TypedArray attr, int attrId, String attrName, - String tag, XmlPullParser parser) throws XmlPullParserException { - if (attr.hasValue(attrId)) + public static void checkAttributeExists(final TypedArray attr, final int attrId, + final String attrName, final String tag, final XmlPullParser parser) + throws XmlPullParserException { + if (attr.hasValue(attrId)) { return; + } throw new ParseException( "No " + attrName + " attribute found in <" + tag + "/>", parser); } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index a38a226f0..aa4c03357 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -1122,10 +1122,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - public void latinIME_onFinishInputViewInternal() { - stop(); - } - /** * Log a change in preferences. * @@ -1208,16 +1204,22 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } /** - * Log a call to LatinIME.onWindowHidden(). + * The IME is finishing; it is either being destroyed, or is about to be hidden. * * UserAction: The user has performed an action that has caused the IME to be closed. They may * have focused on something other than a text field, or explicitly closed it. */ - private static final LogStatement LOGSTATEMENT_LATINIME_ONWINDOWHIDDEN = - new LogStatement("LatinIMEOnWindowHidden", false, false, "isTextTruncated", "text"); - public static void latinIME_onWindowHidden(final int savedSelectionStart, - final int savedSelectionEnd, final InputConnection ic) { - if (ic != null) { + private static final LogStatement LOGSTATEMENT_LATINIME_ONFINISHINPUTVIEWINTERNAL = + new LogStatement("LatinIMEOnFinishInputViewInternal", false, false, "isTextTruncated", + "text"); + public static void latinIME_onFinishInputViewInternal(final boolean finishingInput, + final int savedSelectionStart, final int savedSelectionEnd, final InputConnection ic) { + // The finishingInput flag is set in InputMethodService. It is true if called from + // doFinishInput(), which can be called as part of doStartInput(). This can happen at times + // when the IME is not closing, such as when powering up. The finishinInput flag is false + // if called from finishViews(), which is called from hideWindow() and onDestroy(). These + // are the situations in which we want to finish up the researchLog. + if (ic != null && !finishingInput) { final boolean isTextTruncated; final String text; if (LOG_FULL_TEXTVIEW_CONTENTS) { @@ -1261,8 +1263,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // Assume that OUTPUT_ENTIRE_BUFFER is only true when we don't care about privacy (e.g. // during a live user test), so the normal isPotentiallyPrivate and // isPotentiallyRevealing flags do not apply - researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONWINDOWHIDDEN, isTextTruncated, - text); + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONFINISHINPUTVIEWINTERNAL, + isTextTruncated, text); researchLogger.commitCurrentLogUnit(); getInstance().stop(); } |