diff options
19 files changed, 377 insertions, 39 deletions
diff --git a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java new file mode 100644 index 000000000..2cec14240 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.graphics.Matrix; +import android.graphics.RectF; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.lang.reflect.Method; + +@UsedForTesting +public final class CursorAnchorInfoCompatWrapper { + // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX). + private static Class<?> getCursorAnchorInfoClass() { + try { + return Class.forName("android.view.inputmethod.CursorAnchorInfo"); + } catch (ClassNotFoundException e) { + return null; + } + } + private static final Class<?> CLASS; + private static final Method METHOD_GET_CHARACTER_RECT; + private static final Method METHOD_GET_CHARACTER_RECT_FLAGS; + private static final Method METHOD_GET_COMPOSING_TEXT; + private static final Method METHOD_GET_COMPOSING_TEXT_START; + private static final Method METHOD_GET_MATRIX; + static { + CLASS = getCursorAnchorInfoClass(); + METHOD_GET_CHARACTER_RECT = CompatUtils.getMethod(CLASS, "getCharacterRect", int.class); + METHOD_GET_CHARACTER_RECT_FLAGS = CompatUtils.getMethod(CLASS, "getCharacterRectFlags", + int.class); + METHOD_GET_COMPOSING_TEXT = CompatUtils.getMethod(CLASS, "getComposingText"); + METHOD_GET_COMPOSING_TEXT_START = CompatUtils.getMethod(CLASS, "getComposingTextStart"); + METHOD_GET_MATRIX = CompatUtils.getMethod(CLASS, "getMatrix"); + } + + @UsedForTesting + public static boolean isAvailable() { + return CLASS != null; + } + + public static final int CHARACTER_RECT_TYPE_MASK = 0x0f; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this + * character. Editor authors should not use this flag. + */ + public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible. + */ + public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible. + */ + public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible. + */ + public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle + * for this character. Input method authors should ignore the returned rectangle. + */ + public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4; + + private Object mInstance; + + private CursorAnchorInfoCompatWrapper(final Object instance) { + mInstance = instance; + } + + @UsedForTesting + public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) { + if (!isAvailable()) { + return new CursorAnchorInfoCompatWrapper(null); + } + return new CursorAnchorInfoCompatWrapper(instance); + } + + private static final class FakeHolder { + static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null); + } + + @UsedForTesting + public static CursorAnchorInfoCompatWrapper getFake() { + return FakeHolder.sInstance; + } + + public CharSequence getComposingText() { + return (CharSequence) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT); + } + + private static int COMPOSING_TEXT_START_DEFAULT = -1; + public int getComposingTextStart() { + if (mInstance == null || METHOD_GET_COMPOSING_TEXT_START == null) { + return COMPOSING_TEXT_START_DEFAULT; + } + return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT_START); + } + + public Matrix getMatrix() { + return (Matrix) CompatUtils.invoke(mInstance, null, METHOD_GET_MATRIX); + } + + public RectF getCharacterRect(final int index) { + return (RectF) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT, index); + } + + public int getCharacterRectFlags(final int index) { + if (mInstance == null || METHOD_GET_CHARACTER_RECT_FLAGS == null) { + return CHARACTER_RECT_TYPE_UNSPECIFIED; + } + return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT_FLAGS, index); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index f35126750..140e76879 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.content.res.Resources; import android.preference.PreferenceManager; import android.util.Log; @@ -233,11 +234,21 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } private void setMainKeyboardFrame() { - mMainKeyboardFrame.setVisibility(View.VISIBLE); + mMainKeyboardFrame.setVisibility(hasHardwareKeyboard() ? View.GONE : View.VISIBLE); mEmojiPalettesView.setVisibility(View.GONE); mEmojiPalettesView.stopEmojiPalettes(); } + // TODO: Move this boolean to a member of {@link SettingsValues} and reset it + // at {@link LatinIME#onConfigurationChanged(Configuration)}. + public boolean hasHardwareKeyboard() { + // Copied from {@link InputMethodServce#onEvaluateInputViewShown()}. + final Configuration config = mLatinIME.getResources().getConfiguration(); + final boolean noHardwareKeyboard = config.keyboard == Configuration.KEYBOARD_NOKEYS + || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; + return !noHardwareKeyboard; + } + // Implements {@link KeyboardState.SwitchActions}. @Override public void setEmojiKeyboard() { @@ -249,6 +260,14 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mEmojiPalettesView.setVisibility(View.VISIBLE); } + public void onToggleEmojiKeyboard() { + if (isShowingEmojiPalettes()) { + setAlphabetKeyboard(); + } else { + setEmojiKeyboard(); + } + } + // Implements {@link KeyboardState.SwitchActions}. @Override public void setSymbolsShiftedKeyboard() { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java index 4c2e0dd1d..135423393 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java @@ -38,6 +38,9 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { public static final int THEME_ID_LXX_DARK = 4; public static final int DEFAULT_THEME_ID = THEME_ID_KLP; + // TODO: Update this constant once the *next* version becomes available. + public static final int VERSION_CODES_LXX = 21; + private static final KeyboardTheme[] KEYBOARD_THEMES = { new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS, // This has never been selected because we support ICS or later. @@ -47,8 +50,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { VERSION_CODES.ICE_CREAM_SANDWICH), new KeyboardTheme(THEME_ID_LXX_LIGHT, R.style.KeyboardTheme_LXX_Light, // Default theme for LXX. - // TODO: Update this constant once the *next* version becomes available. - VERSION_CODES.CUR_DEVELOPMENT), + VERSION_CODES_LXX), new KeyboardTheme(THEME_ID_LXX_DARK, R.style.KeyboardTheme_LXX_Dark, VERSION_CODES.BASE), }; @@ -100,12 +102,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { } private static int getSdkVersion() { - final int sdkVersion = Build.VERSION.SDK_INT; - // TODO: Consider to remove this check once the *next* version becomes available. - if (sdkVersion > VERSION_CODES.KITKAT) { - return VERSION_CODES.CUR_DEVELOPMENT; - } - return sdkVersion; + return Build.VERSION.SDK_INT; } @UsedForTesting diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 702efb3d7..1ef53a65d 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -46,6 +46,7 @@ import com.android.inputmethod.keyboard.internal.GestureTrailsDrawingPreview; import com.android.inputmethod.keyboard.internal.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; +import com.android.inputmethod.keyboard.internal.KeyPreviewView; import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; @@ -764,6 +765,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, final int languageOnSpacebarFormatType, final boolean hasMultipleEnabledIMEsOrSubtypes) { + if (subtypeChanged) { + KeyPreviewView.clearTextCache(); + } mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType; mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java index 360faf829..24538605a 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java @@ -17,7 +17,10 @@ package com.android.inputmethod.keyboard.internal; import android.content.Context; +import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.TextPaint; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; @@ -26,6 +29,8 @@ import android.widget.TextView; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.R; +import java.util.HashSet; + /** * The pop up key preview view. */ @@ -34,6 +39,9 @@ public class KeyPreviewView extends TextView { public static final int POSITION_LEFT = 1; public static final int POSITION_RIGHT = 2; + private final Rect mBackgroundPadding = new Rect(); + private static final HashSet<String> sNoScaleXTextSet = new HashSet<>(); + public KeyPreviewView(final Context context, final AttributeSet attrs) { this(context, attrs, 0); } @@ -58,7 +66,48 @@ public class KeyPreviewView extends TextView { setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams)); setTypeface(key.selectPreviewTypeface(drawParams)); // TODO Should take care of temporaryShiftLabel here. - setText(key.getPreviewLabel()); + setTextAndScaleX(key.getPreviewLabel()); + } + + private void setTextAndScaleX(final String text) { + setTextScaleX(1.0f); + setText(text); + if (sNoScaleXTextSet.contains(text)) { + return; + } + // TODO: Override {@link #setBackground(Drawable)} that is supported from API 16 and + // calculate maximum text width. + final Drawable background = getBackground(); + if (background == null) { + return; + } + background.getPadding(mBackgroundPadding); + final int maxWidth = background.getIntrinsicWidth() - mBackgroundPadding.left + - mBackgroundPadding.right; + final float width = getTextWidth(text, getPaint()); + if (width <= maxWidth) { + sNoScaleXTextSet.add(text); + return; + } + setTextScaleX(maxWidth / width); + } + + public static void clearTextCache() { + sNoScaleXTextSet.clear(); + } + + private static float getTextWidth(final String text, final TextPaint paint) { + if (TextUtils.isEmpty(text)) { + return 0.0f; + } + final int len = text.length(); + final float[] widths = new float[len]; + final int count = paint.getTextWidths(text, 0, len, widths); + float width = 0; + for (int i = 0; i < count; i++) { + width += widths[i]; + } + return width; } // Background state set diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2e3cd6b6f..9b629ca14 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -145,6 +145,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // If it turns out we need several, it will get grown seamlessly. final SparseArray<HardwareEventDecoder> mHardwareEventDecoders = new SparseArray<>(1); + // TODO: Move these {@link View}s to {@link KeyboardSwitcher}. + private View mInputView; private View mExtractArea; private View mKeyPreviewBackingView; private SuggestionStripView mSuggestionStripView; @@ -153,6 +155,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); + private final SpecialKeyDetector mSpecialKeyDetector = new SpecialKeyDetector(); // Object for reacting to adding/removing a dictionary pack. private final BroadcastReceiver mDictionaryPackInstallReceiver = @@ -709,6 +712,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void setInputView(final View view) { super.setInputView(view); + mInputView = view; mExtractArea = getWindow().getWindow().getDecorView() .findViewById(android.R.id.extractArea); mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); @@ -1079,6 +1083,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (visibleKeyboardView == null || !hasSuggestionStripView()) { return; } + final boolean hasHardwareKeyboard = mKeyboardSwitcher.hasHardwareKeyboard(); + if (hasHardwareKeyboard && visibleKeyboardView.getVisibility() == View.GONE) { + // If there is a hardware keyboard and a visible software keyboard view has been hidden, + // no visual element will be shown on the screen. + outInsets.touchableInsets = mInputView.getHeight(); + outInsets.visibleTopInsets = mInputView.getHeight(); + return; + } final int adjustedBackingHeight = getAdjustedBackingViewHeight(); final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE); final int backingHeight = backingGone ? 0 : adjustedBackingHeight; @@ -1111,7 +1123,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override + public boolean onEvaluateInputViewShown() { + // Always show {@link InputView}. + return true; + } + + @Override public boolean onEvaluateFullscreenMode() { + if (mKeyboardSwitcher.hasHardwareKeyboard()) { + // If there is a hardware keyboard, disable full screen mode. + return false; + } // Reread resource value here, because this method is called by the framework as needed. final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { @@ -1568,6 +1590,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Hooks for hardware keyboard @Override public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) { + mSpecialKeyDetector.onKeyDown(keyEvent); if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { return super.onKeyDown(keyCode, keyEvent); } @@ -1587,12 +1610,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override - public boolean onKeyUp(final int keyCode, final KeyEvent event) { - final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode(); + public boolean onKeyUp(final int keyCode, final KeyEvent keyEvent) { + mSpecialKeyDetector.onKeyUp(keyEvent); + if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { + return super.onKeyUp(keyCode, keyEvent); + } + final long keyIdentifier = keyEvent.getDeviceId() << 32 + keyEvent.getKeyCode(); if (mInputLogic.mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) { return true; } - return super.onKeyUp(keyCode, event); + return super.onKeyUp(keyCode, keyEvent); } // onKeyDown and onKeyUp are the main events we are interested in. There are two more events diff --git a/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java b/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java new file mode 100644 index 000000000..9d6c69ae7 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014, 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; + +import android.view.KeyEvent; + +final class SpecialKeyDetector { + /** + * Record a down key event. + * @param keyEvent a down key event. + */ + public void onKeyDown(final KeyEvent keyEvent) { + } + + /** + * Record an up key event. + * @param keyEvent an up key event. + */ + public void onKeyUp(final KeyEvent keyEvent) { + } +} diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp index 278f2b199..f7179f68d 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp @@ -234,8 +234,8 @@ bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition( bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds, const int wordId, const BigramProperty *const bigramProperty, bool *const outAddedNewEntry) { if (!mBigramPolicy->addNewEntry(prevWordIds[0], wordId, bigramProperty, outAddedNewEntry)) { - AKLOGE("Cannot add new bigram entry. terminalId: %d, targetTerminalId: %d", - sourcePtNodeParams->getTerminalId(), targetPtNodeParam->getTerminalId()); + AKLOGE("Cannot add new bigram entry. prevWordId: %d, wordId: %d", + prevWordIds[0], wordId); return false; } const int ptNodePos = diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp index 5dc91ba10..f3bc4a0cb 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp @@ -46,7 +46,7 @@ ProbabilityEntry LanguageModelDictContent::getNgramProbabilityEntry( bool LanguageModelDictContent::setNgramProbabilityEntry(const WordIdArrayView prevWordIds, const int terminalId, const ProbabilityEntry *const probabilityEntry) { - const int bitmapEntryIndex = getBitmapEntryIndex(prevWordIds); + const int bitmapEntryIndex = createAndGetBitmapEntryIndex(prevWordIds); if (bitmapEntryIndex == TrieMap::INVALID_INDEX) { return false; } @@ -80,6 +80,19 @@ bool LanguageModelDictContent::runGCInner( return true; } +int LanguageModelDictContent::createAndGetBitmapEntryIndex(const WordIdArrayView prevWordIds) { + if (prevWordIds.empty()) { + return mTrieMap.getRootBitmapEntryIndex(); + } + const int lastBitmapEntryIndex = + getBitmapEntryIndex(prevWordIds.limit(prevWordIds.size() - 1)); + if (lastBitmapEntryIndex == TrieMap::INVALID_INDEX) { + return TrieMap::INVALID_INDEX; + } + return mTrieMap.getNextLevelBitmapEntryIndex(prevWordIds[prevWordIds.size() - 1], + lastBitmapEntryIndex); +} + int LanguageModelDictContent::getBitmapEntryIndex(const WordIdArrayView prevWordIds) const { int bitmapEntryIndex = mTrieMap.getRootBitmapEntryIndex(); for (const int wordId : prevWordIds) { diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h index 18f2e0170..104ee2520 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h @@ -76,7 +76,7 @@ class LanguageModelDictContent { bool runGCInner(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, const TrieMap::TrieMapRange trieMapRange, const int nextLevelBitmapEntryIndex, int *const outNgramCount); - + int createAndGetBitmapEntryIndex(const WordIdArrayView prevWordIds); int getBitmapEntryIndex(const WordIdArrayView prevWordIds) const; }; } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h index feff6b57f..ed77bd20e 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h @@ -21,6 +21,8 @@ #include <cstdint> #include "defines.h" +#include "suggest/core/dictionary/property/bigram_property.h" +#include "suggest/core/dictionary/property/unigram_property.h" #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" #include "suggest/policyimpl/dictionary/utils/historical_info.h" @@ -45,6 +47,20 @@ class ProbabilityEntry { const HistoricalInfo *const historicalInfo) : mFlags(flags), mProbability(probability), mHistoricalInfo(*historicalInfo) {} + // Create from unigram property. + // TODO: Set flags. + ProbabilityEntry(const UnigramProperty *const unigramProperty) + : mFlags(0), mProbability(unigramProperty->getProbability()), + mHistoricalInfo(unigramProperty->getTimestamp(), unigramProperty->getLevel(), + unigramProperty->getCount()) {} + + // Create from bigram property. + // TODO: Set flags. + ProbabilityEntry(const BigramProperty *const bigramProperty) + : mFlags(0), mProbability(bigramProperty->getProbability()), + mHistoricalInfo(bigramProperty->getTimestamp(), bigramProperty->getLevel(), + bigramProperty->getCount()) {} + const ProbabilityEntry createEntryWithUpdatedProbability(const int probability) const { return ProbabilityEntry(mFlags, probability, &mHistoricalInfo); } @@ -54,6 +70,10 @@ class ProbabilityEntry { return ProbabilityEntry(mFlags, mProbability, historicalInfo); } + bool isValid() const { + return (mProbability != NOT_A_PROBABILITY) || hasHistoricalInfo(); + } + bool hasHistoricalInfo() const { return mHistoricalInfo.isValid(); } @@ -89,7 +109,7 @@ class ProbabilityEntry { static ProbabilityEntry decode(const uint64_t encodedEntry, const bool hasHistoricalInfo) { if (hasHistoricalInfo) { const int flags = readFromEncodedEntry(encodedEntry, - Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, + Ver4DictConstants::FLAGS_IN_LANGUAGE_MODEL_SIZE, Ver4DictConstants::TIME_STAMP_FIELD_SIZE + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE + Ver4DictConstants::WORD_COUNT_FIELD_SIZE); @@ -106,7 +126,7 @@ class ProbabilityEntry { return ProbabilityEntry(flags, NOT_A_PROBABILITY, &historicalInfo); } else { const int flags = readFromEncodedEntry(encodedEntry, - Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, + Ver4DictConstants::FLAGS_IN_LANGUAGE_MODEL_SIZE, Ver4DictConstants::PROBABILITY_SIZE); const int probability = readFromEncodedEntry(encodedEntry, Ver4DictConstants::PROBABILITY_SIZE, 0 /* pos */); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp index 93d4e562d..e622442ba 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp @@ -46,7 +46,7 @@ const int Ver4DictConstants::SHORTCUT_BUFFERS_INDEX = const int Ver4DictConstants::NOT_A_TERMINAL_ID = -1; const int Ver4DictConstants::PROBABILITY_SIZE = 1; -const int Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE = 1; +const int Ver4DictConstants::FLAGS_IN_LANGUAGE_MODEL_SIZE = 1; const int Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE = 3; const int Ver4DictConstants::NOT_A_TERMINAL_ADDRESS = 0; const int Ver4DictConstants::TERMINAL_ID_FIELD_SIZE = 4; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h index 6950ca70f..8d29f60d4 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h @@ -41,7 +41,7 @@ class Ver4DictConstants { static const int NOT_A_TERMINAL_ID; static const int PROBABILITY_SIZE; - static const int FLAGS_IN_PROBABILITY_FILE_SIZE; + static const int FLAGS_IN_LANGUAGE_MODEL_SIZE; static const int TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE; static const int NOT_A_TERMINAL_ADDRESS; static const int TERMINAL_ID_FIELD_SIZE; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp index 857222f5d..2c848cb29 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp @@ -145,10 +145,11 @@ bool Ver4PatriciaTrieNodeWriter::updatePtNodeUnigramProperty( const ProbabilityEntry originalProbabilityEntry = mBuffers->getLanguageModelDictContent()->getProbabilityEntry( toBeUpdatedPtNodeParams->getTerminalId()); - const ProbabilityEntry probabilityEntry = createUpdatedEntryFrom(&originalProbabilityEntry, - unigramProperty); + const ProbabilityEntry probabilityEntryOfUnigramProperty = ProbabilityEntry(unigramProperty); + const ProbabilityEntry updatedProbabilityEntry = + createUpdatedEntryFrom(&originalProbabilityEntry, &probabilityEntryOfUnigramProperty); return mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry( - toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry); + toBeUpdatedPtNodeParams->getTerminalId(), &updatedProbabilityEntry); } bool Ver4PatriciaTrieNodeWriter::updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC( @@ -216,16 +217,36 @@ bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition( } // Write probability. ProbabilityEntry newProbabilityEntry; + const ProbabilityEntry probabilityEntryOfUnigramProperty = ProbabilityEntry(unigramProperty); const ProbabilityEntry probabilityEntryToWrite = createUpdatedEntryFrom( - &newProbabilityEntry, unigramProperty); + &newProbabilityEntry, &probabilityEntryOfUnigramProperty); return mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry( terminalId, &probabilityEntryToWrite); } bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds, const int wordId, const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) { + // TODO: Support n-gram. + LanguageModelDictContent *const languageModelDictContent = + mBuffers->getMutableLanguageModelDictContent(); + const ProbabilityEntry probabilityEntry = + languageModelDictContent->getNgramProbabilityEntry( + prevWordIds.limit(1 /* maxSize */), wordId); + const ProbabilityEntry probabilityEntryOfBigramProperty(bigramProperty); + const ProbabilityEntry updatedProbabilityEntry = createUpdatedEntryFrom( + &probabilityEntry, &probabilityEntryOfBigramProperty); + if (!languageModelDictContent->setNgramProbabilityEntry( + prevWordIds.limit(1 /* maxSize */), wordId, &updatedProbabilityEntry)) { + AKLOGE("Cannot add new ngram entry. prevWordId: %d, wordId: %d", + prevWordIds[0], wordId); + return false; + } + if (!probabilityEntry.isValid() && outAddedNewBigram) { + *outAddedNewBigram = true; + } + // TODO: Remove. if (!mBigramPolicy->addNewEntry(prevWordIds[0], wordId, bigramProperty, outAddedNewBigram)) { - AKLOGE("Cannot add new bigram entry. terminalId: %d, targetTerminalId: %d", + AKLOGE("Cannot add new bigram entry. prevWordId: %d, wordId: %d", prevWordIds[0], wordId); return false; } @@ -234,6 +255,7 @@ bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds bool Ver4PatriciaTrieNodeWriter::removeNgramEntry(const WordIdArrayView prevWordIds, const int wordId) { + // TODO: Remove. return mBigramPolicy->removeEntry(prevWordIds[0], wordId); } @@ -352,20 +374,19 @@ bool Ver4PatriciaTrieNodeWriter::writePtNodeAndGetTerminalIdAndAdvancePosition( const ProbabilityEntry Ver4PatriciaTrieNodeWriter::createUpdatedEntryFrom( const ProbabilityEntry *const originalProbabilityEntry, - const UnigramProperty *const unigramProperty) const { + const ProbabilityEntry *const probabilityEntry) const { // TODO: Consolidate historical info and probability. if (mHeaderPolicy->hasHistoricalInfoOfWords()) { - const HistoricalInfo historicalInfoForUpdate(unigramProperty->getTimestamp(), - unigramProperty->getLevel(), unigramProperty->getCount()); const HistoricalInfo updatedHistoricalInfo = ForgettingCurveUtils::createUpdatedHistoricalInfo( originalProbabilityEntry->getHistoricalInfo(), - unigramProperty->getProbability(), &historicalInfoForUpdate, mHeaderPolicy); + probabilityEntry->getProbability(), probabilityEntry->getHistoricalInfo(), + mHeaderPolicy); return originalProbabilityEntry->createEntryWithUpdatedHistoricalInfo( &updatedHistoricalInfo); } else { return originalProbabilityEntry->createEntryWithUpdatedProbability( - unigramProperty->getProbability()); + probabilityEntry->getProbability()); } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h index 6703dba04..5d73b6ea3 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h @@ -98,12 +98,12 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter { const PtNodeParams *const ptNodeParams, int *const outTerminalId, int *const ptNodeWritingPos); - // Create updated probability entry using given unigram property. In addition to the + // Create updated probability entry using given probability property. In addition to the // probability, this method updates historical information if needed. - // TODO: Update flags belonging to the unigram property. + // TODO: Update flags. const ProbabilityEntry createUpdatedEntryFrom( const ProbabilityEntry *const originalProbabilityEntry, - const UnigramProperty *const unigramProperty) const; + const ProbabilityEntry *const probabilityEntry) const; bool updatePtNodeFlags(const int ptNodePos, const bool isBlacklisted, const bool isNotAWord, const bool isTerminal, const bool hasMultipleChars); diff --git a/native/jni/src/utils/int_array_view.h b/native/jni/src/utils/int_array_view.h index c1ddc9812..53f2d2971 100644 --- a/native/jni/src/utils/int_array_view.h +++ b/native/jni/src/utils/int_array_view.h @@ -91,6 +91,11 @@ class IntArrayView { return mPtr + mSize; } + // Returns the view whose size is smaller than or equal to the given count. + const IntArrayView limit(const size_t maxSize) const { + return IntArrayView(mPtr, std::min(maxSize, mSize)); + } + private: DISALLOW_ASSIGNMENT_OPERATOR(IntArrayView); diff --git a/native/jni/tests/utils/int_array_view_test.cpp b/native/jni/tests/utils/int_array_view_test.cpp index bd843ab02..ecc451af0 100644 --- a/native/jni/tests/utils/int_array_view_test.cpp +++ b/native/jni/tests/utils/int_array_view_test.cpp @@ -53,9 +53,24 @@ TEST(IntArrayViewTest, TestConstructFromArray) { TEST(IntArrayViewTest, TestConstructFromObject) { const int object = 10; const auto intArrayView = IntArrayView::fromObject(&object); - EXPECT_EQ(1, intArrayView.size()); + EXPECT_EQ(1u, intArrayView.size()); EXPECT_EQ(object, intArrayView[0]); } +TEST(IntArrayViewTest, TestLimit) { + const std::vector<int> intVector = {3, 2, 1, 0, -1, -2}; + IntArrayView intArrayView(intVector); + + EXPECT_TRUE(intArrayView.limit(0).empty()); + EXPECT_EQ(intArrayView.size(), intArrayView.limit(intArrayView.size()).size()); + EXPECT_EQ(intArrayView.size(), intArrayView.limit(1000).size()); + + IntArrayView subView = intArrayView.limit(4); + EXPECT_EQ(4u, subView.size()); + for (size_t i = 0; i < subView.size(); ++i) { + EXPECT_EQ(intVector[i], subView[i]); + } +} + } // namespace } // namespace latinime diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java index 0c7e4000e..45e1558a8 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java @@ -20,6 +20,7 @@ import static com.android.inputmethod.keyboard.KeyboardTheme.THEME_ID_ICS; import static com.android.inputmethod.keyboard.KeyboardTheme.THEME_ID_KLP; import static com.android.inputmethod.keyboard.KeyboardTheme.THEME_ID_LXX_DARK; import static com.android.inputmethod.keyboard.KeyboardTheme.THEME_ID_LXX_LIGHT; +import static com.android.inputmethod.keyboard.KeyboardTheme.VERSION_CODES_LXX; import android.content.SharedPreferences; import android.os.Build.VERSION_CODES; @@ -31,9 +32,6 @@ import android.test.suitebuilder.annotation.SmallTest; public class KeyboardThemeTests extends AndroidTestCase { private SharedPreferences mPrefs; - // TODO: Remove this constant once the *next* version becomes available. - private static final int VERSION_CODES_LXX = VERSION_CODES.CUR_DEVELOPMENT; - private static final int THEME_ID_NULL = -1; private static final int THEME_ID_UNKNOWN = -2; private static final int THEME_ID_ILLEGAL = -3; diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java index f937de89a..b494ad37b 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java @@ -25,7 +25,7 @@ import com.android.inputmethod.keyboard.layout.Malayalam.MalayalamCustomizer; import java.util.Locale; /** - * ta_IN: Malayalam (India)/malayalam + * ml_IN: Malayalam (India)/malayalam */ @SmallTest public final class TestsMalayalamIN extends LayoutTestsBase { |