Merge "Make dict log cleanup." into lmp-dev
diff --git a/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 0000000..314c521
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 0000000..11363b1
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 0000000..32a5b05
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 0000000..a22c463
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/menu/add_style.xml b/java/res/menu/add_style.xml
new file mode 100644
index 0000000..d1cab4b
--- /dev/null
+++ b/java/res/menu/add_style.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/action_add_style"
+ android:icon="@drawable/ic_add_circle_wht_24dp"
+ android:title="@string/add_style"
+ android:showAsAction="always" />
+</menu>
\ No newline at end of file
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 003b011..9a22273 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -52,7 +52,9 @@
<attr name="spacebarIconWidthRatio" format="float" />
<!-- 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.-->
+ <!-- Popup hint letter string-->
+ <attr name="keyPopupHintLetter" format="string" />
+ <!-- Bottom padding of popup hint letter to the edge of the key.-->
<attr name="keyPopupHintLetterPadding" format="dimension" />
<!-- Right padding of shifted letter hint to the edge of the key.-->
<attr name="keyShiftedLetterHintPadding" format="dimension" />
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 6118ce1..a6f390c 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -60,6 +60,8 @@
<item name="keyPreviewTextColor">@color/key_text_color_holo</item>
<!-- A negative value to disable key text shadow layer. -->
<item name="keyTextShadowRadius">-1.0</item>
+ <!-- U+2026: "…" HORIZONTAL ELLIPSIS -->
+ <item name="keyPopupHintLetter">…</item>
</style>
<style
name="MainKeyboardView.ICS"
diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml
index 1933860..8782a76 100644
--- a/java/res/values/themes-klp.xml
+++ b/java/res/values/themes-klp.xml
@@ -60,6 +60,8 @@
<item name="keyPreviewTextColor">@color/key_text_color_holo</item>
<!-- A negative value to disable key text shadow layer. -->
<item name="keyTextShadowRadius">-1.0</item>
+ <!-- U+2026: "…" HORIZONTAL ELLIPSIS -->
+ <item name="keyPopupHintLetter">…</item>
</style>
<style
name="MainKeyboardView.KLP"
diff --git a/java/res/values/themes-lxx-dark.xml b/java/res/values/themes-lxx-dark.xml
index 0a13158..fa6aa62 100644
--- a/java/res/values/themes-lxx-dark.xml
+++ b/java/res/values/themes-lxx-dark.xml
@@ -61,6 +61,7 @@
<item name="keyPreviewTextColor">@color/key_text_color_lxx_dark</item>
<!-- A negative value to disable key text shadow layer. -->
<item name="keyTextShadowRadius">-1.0</item>
+ <item name="keyPopupHintLetter"></item> <!-- No popup hint letter -->
</style>
<style
name="MainKeyboardView.LXX_Dark"
diff --git a/java/res/values/themes-lxx-light.xml b/java/res/values/themes-lxx-light.xml
index eccecdd..e7350f9 100644
--- a/java/res/values/themes-lxx-light.xml
+++ b/java/res/values/themes-lxx-light.xml
@@ -61,6 +61,7 @@
<item name="keyPreviewTextColor">@color/key_text_color_lxx_light</item>
<!-- A negative value to disable key text shadow layer. -->
<item name="keyTextShadowRadius">-1.0</item>
+ <item name="keyPopupHintLetter"></item> <!-- No popup hint letter -->
</style>
<style
name="MainKeyboardView.LXX_Light"
diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml
index 50530e1..770bf38 100644
--- a/java/res/xml/key_styles_enter.xml
+++ b/java/res/xml/key_styles_enter.xml
@@ -255,6 +255,7 @@
<!-- Enter key style -->
<key-style
latin:styleName="defaultEnterKeyStyle"
+ latin:keySpec="!icon/enter_key|!code/key_enter"
latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio|followFunctionalTextColor"
latin:keyActionFlags="noKeyPreview"
latin:backgroundType="action"
diff --git a/java/res/xml/key_styles_number.xml b/java/res/xml/key_styles_number.xml
index df4448c..f754b99 100644
--- a/java/res/xml/key_styles_number.xml
+++ b/java/res/xml/key_styles_number.xml
@@ -122,12 +122,4 @@
latin:keySpec="!icon/space_key_for_number_layout|!code/key_space"
latin:keyActionFlags="enableLongPress"
latin:parentStyle="numKeyBaseStyle" />
- <!-- Override defaultEnterKeyStyle in key_styles_enter.xml -->
- <key-style
- latin:styleName="defaultEnterKeyStyle"
- latin:keySpec="!icon/enter_key|!code/key_enter"
- latin:keyLabelFlags="preserveCase|autoXScale|followKeyLargeLabelRatio"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional"
- latin:parentStyle="navigateMoreKeysStyle" />
</merge>
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
index deb6809..afbe8c8 100644
--- a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -31,6 +31,9 @@
private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
View.class, "setPaddingRelative",
int.class, int.class, int.class, int.class);
+ // Note that View.setElevation(float) has been introduced in API level 21.
+ private static final Method METHOD_setElevation = CompatUtils.getMethod(
+ View.class, "setElevation", float.class);
private ViewCompatUtils() {
// This utility class is not publicly instantiable.
@@ -51,4 +54,11 @@
}
CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
}
+
+ public static void setElevation(final View view, final float elevation) {
+ if (METHOD_setElevation == null) {
+ return;
+ }
+ CompatUtils.invoke(view, null, METHOD_setElevation, elevation);
+ }
}
diff --git a/java/src/com/android/inputmethod/event/InputTransaction.java b/java/src/com/android/inputmethod/event/InputTransaction.java
index 5bc9111..b18bf56 100644
--- a/java/src/com/android/inputmethod/event/InputTransaction.java
+++ b/java/src/com/android/inputmethod/event/InputTransaction.java
@@ -33,7 +33,7 @@
// Initial conditions
public final SettingsValues mSettingsValues;
- public final Event mEvent;
+ private final Event mEvent;
public final long mTimestamp;
public final int mSpaceState;
public final int mShiftState;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index f967f62..5af0be6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -29,6 +29,7 @@
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
@@ -48,6 +49,7 @@
* @attr ref R.styleable#KeyboardView_spacebarBackground
* @attr ref R.styleable#KeyboardView_spacebarIconWidthRatio
* @attr ref R.styleable#KeyboardView_keyHintLetterPadding
+ * @attr ref R.styleable#KeyboardView_keyPopupHintLetter
* @attr ref R.styleable#KeyboardView_keyPopupHintLetterPadding
* @attr ref R.styleable#KeyboardView_keyShiftedLetterHintPadding
* @attr ref R.styleable#KeyboardView_keyTextShadowRadius
@@ -74,6 +76,7 @@
// XML attributes
private final KeyVisualAttributes mKeyVisualAttributes;
private final float mKeyHintLetterPadding;
+ private final String mKeyPopupHintLetter;
private final float mKeyPopupHintLetterPadding;
private final float mKeyShiftedLetterHintPadding;
private final float mKeyTextShadowRadius;
@@ -85,9 +88,6 @@
private final Rect mKeyBackgroundPadding = new Rect();
private static final float KET_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
- // HORIZONTAL ELLIPSIS "...", character for popup hint.
- private static final String POPUP_HINT_CHAR = "\u2026";
-
// The maximum key label width in the proportion to the key width.
private static final float MAX_LABEL_RATIO = 0.90f;
@@ -132,6 +132,8 @@
R.styleable.KeyboardView_spacebarIconWidthRatio, 1.0f);
mKeyHintLetterPadding = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_keyHintLetterPadding, 0.0f);
+ mKeyPopupHintLetter = keyboardViewAttr.getString(
+ R.styleable.KeyboardView_keyPopupHintLetter);
mKeyPopupHintLetterPadding = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_keyPopupHintLetterPadding, 0.0f);
mKeyShiftedLetterHintPadding = keyboardViewAttr.getDimension(
@@ -468,6 +470,9 @@
// Draw popup hint "..." at the bottom right corner of the key.
protected void drawKeyPopupHint(final Key key, final Canvas canvas, final Paint paint,
final KeyDrawParams params) {
+ if (TextUtils.isEmpty(mKeyPopupHintLetter)) {
+ return;
+ }
final int keyWidth = key.getDrawWidth();
final int keyHeight = key.getHeight();
@@ -478,7 +483,7 @@
final float hintX = keyWidth - mKeyHintLetterPadding
- TypefaceUtils.getReferenceCharWidth(paint) / 2.0f;
final float hintY = keyHeight - mKeyPopupHintLetterPadding;
- canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint);
+ canvas.drawText(mKeyPopupHintLetter, hintX, hintY, paint);
}
protected static void drawIcon(final Canvas canvas, final Drawable icon, final int x,
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 4adc28d..c7c3aaa 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -295,7 +295,8 @@
}
}
- public void postResetCaches(final boolean tryResumeSuggestions, final int remainingTries) {
+ public void postResetInputConnectionCaches(final boolean tryResumeSuggestions,
+ final int remainingTries) {
removeMessages(MSG_RESET_CACHES);
sendMessage(obtainMessage(MSG_RESET_CACHES, tryResumeSuggestions ? 1 : 0,
remainingTries, null));
@@ -762,9 +763,12 @@
private static class EditorChangeInfo {
public final boolean mIsSameInputType;
public final boolean mHasSameOrientation;
- public EditorChangeInfo(final boolean isSameInputType, final boolean hasSameOrientation) {
+ public final boolean mCanReachInputConnection;
+ public EditorChangeInfo(final boolean isSameInputType, final boolean hasSameOrientation,
+ final boolean canReachInputConnection) {
mIsSameInputType = isSameInputType;
mHasSameOrientation = hasSameOrientation;
+ mCanReachInputConnection = canReachInputConnection;
}
}
@@ -772,16 +776,66 @@
private void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) {
super.onStartInput(editorInfo, restarting);
+ if (editorInfo == null) {
+ Log.e(TAG, "Null EditorInfo in onStartInput()");
+ return;
+ }
SettingsValues currentSettingsValues = mSettings.getCurrent();
- mLastEditorChangeInfo = new EditorChangeInfo(
- currentSettingsValues.isSameInputType(editorInfo),
- currentSettingsValues.hasSameOrientation(getResources().getConfiguration()));
+ final boolean isSameInputType = currentSettingsValues.isSameInputType(editorInfo);
+ final boolean hasSameOrientation =
+ currentSettingsValues.hasSameOrientation(getResources().getConfiguration());
+ mRichImm.clearSubtypeCaches();
+ final boolean inputTypeChanged = !isSameInputType;
+ final boolean isDifferentTextField = !restarting || inputTypeChanged;
+ if (isDifferentTextField || !hasSameOrientation) {
+ loadSettings();
+ currentSettingsValues = mSettings.getCurrent();
+ }
+
+ // Note: the following does a round-trip IPC on the main thread: be careful
+ final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+ final Suggest suggest = mInputLogic.mSuggest;
+ if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) {
+ // TODO: Do this automatically.
+ resetSuggest();
+ }
+ if (isDifferentTextField && currentSettingsValues.mAutoCorrectionEnabledPerUserSettings) {
+ suggest.setAutoCorrectionThreshold(currentSettingsValues.mAutoCorrectionThreshold);
+ }
+
+ // The app calling setText() has the effect of clearing the composing
+ // span, so we should reset our state unconditionally, even if restarting is true.
+ // We also tell the input logic about the combining rules for the current subtype, so
+ // it can adjust its combiners if needed.
+ mInputLogic.startInput(mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype());
+ // TODO[IL]: Can the following be moved to InputLogic#startInput?
+ final boolean canReachInputConnection;
+ if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
+ editorInfo.initialSelStart, editorInfo.initialSelEnd,
+ false /* shouldFinishComposition */)) {
+ // Sometimes, while rotating, for some reason the framework tells the app we are not
+ // connected to it and that means we can't refresh the cache. In this case, schedule a
+ // refresh later.
+ // We try resetting the caches up to 5 times before giving up.
+ mHandler.postResetInputConnectionCaches(isDifferentTextField || !hasSameOrientation,
+ 5 /* remainingTries */);
+ canReachInputConnection = false;
+ } else {
+ // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
+ // effort to work around this bug.
+ mInputLogic.mConnection.tryFixLyingCursorPosition();
+ mHandler.postResumeSuggestions(true /* shouldIncludeResumedWordInSuggestions */,
+ true /* shouldDelay */);
+ canReachInputConnection = true;
+ }
+
+ mLastEditorChangeInfo = new EditorChangeInfo(isSameInputType, hasSameOrientation,
+ canReachInputConnection);
}
@SuppressWarnings("deprecation")
private void onStartInputViewInternal(final EditorInfo editorInfo, final boolean restarting) {
super.onStartInputView(editorInfo, restarting);
- mRichImm.clearSubtypeCaches();
final KeyboardSwitcher switcher = mKeyboardSwitcher;
switcher.updateKeyboardTheme();
final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView();
@@ -837,56 +891,13 @@
// Note: This call should be done by InputMethodService?
updateFullscreenMode();
- // The app calling setText() has the effect of clearing the composing
- // span, so we should reset our state unconditionally, even if restarting is true.
- // We also tell the input logic about the combining rules for the current subtype, so
- // it can adjust its combiners if needed.
- mInputLogic.startInput(mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype());
-
- // Note: the following does a round-trip IPC on the main thread: be careful
- final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
- final Suggest suggest = mInputLogic.mSuggest;
- if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) {
- // TODO: Do this automatically.
- resetSuggest();
- }
-
- // TODO[IL]: Can the following be moved to InputLogic#startInput?
- final boolean canReachInputConnection;
- if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
- editorInfo.initialSelStart, editorInfo.initialSelEnd,
- false /* shouldFinishComposition */)) {
- // Sometimes, while rotating, for some reason the framework tells the app we are not
- // connected to it and that means we can't refresh the cache. In this case, schedule a
- // refresh later.
- // We try resetting the caches up to 5 times before giving up.
- mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
- // mLastSelection{Start,End} are reset later in this method, don't need to do it here
- canReachInputConnection = false;
- } else {
- // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
- // effort to work around this bug.
- mInputLogic.mConnection.tryFixLyingCursorPosition();
- mHandler.postResumeSuggestions(true /* shouldIncludeResumedWordInSuggestions */,
- true /* shouldDelay */);
- canReachInputConnection = true;
- }
-
- if (isDifferentTextField || !mLastEditorChangeInfo.mHasSameOrientation) {
- loadSettings();
- }
final SettingsValues currentSettingsValues = mSettings.getCurrent();
if (isDifferentTextField) {
mainKeyboardView.closing();
- if (currentSettingsValues.mAutoCorrectionEnabledPerUserSettings) {
- suggest.setAutoCorrectionThreshold(
- currentSettingsValues.mAutoCorrectionThreshold);
- }
-
switcher.loadKeyboard(editorInfo, currentSettingsValues, getCurrentAutoCapsState(),
getCurrentRecapitalizeState());
- if (!canReachInputConnection) {
+ if (!mLastEditorChangeInfo.mCanReachInputConnection) {
// If we can't reach the input connection, we will call loadKeyboard again later,
// so we need to save its state now. The call will be done in #retryResetCaches.
switcher.saveKeyboardState();
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index a6b3b71..ea63cef 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.latin;
import android.inputmethodservice.InputMethodService;
+import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -811,4 +812,25 @@
public boolean isCursorPositionKnown() {
return INVALID_CURSOR_POSITION != mExpectedSelStart;
}
+
+ /**
+ * Work around a bug that was present before Jelly Bean upon rotation.
+ *
+ * Before Jelly Bean, there is a bug where setComposingRegion and other committing
+ * functions on the input connection get ignored until the cursor moves. This method works
+ * around the bug by wiggling the cursor first, which reactivates the connection and has
+ * the subsequent methods work, then restoring it to its original position.
+ *
+ * On platforms on which this method is not present, this is a no-op.
+ */
+ public void maybeMoveTheCursorAroundAndRestoreToWorkaroundABug() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ if (mExpectedSelStart > 0) {
+ mIC.setSelection(mExpectedSelStart - 1, mExpectedSelStart - 1);
+ } else {
+ mIC.setSelection(mExpectedSelStart + 1, mExpectedSelStart + 1);
+ }
+ mIC.setSelection(mExpectedSelStart, mExpectedSelEnd);
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 9e20abc..2be7920 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -426,12 +426,17 @@
cancelDoubleSpacePeriodCountdown();
}
- if (processedEvent.isConsumed()) {
- handleConsumedEvent(inputTransaction);
- } else if (processedEvent.isFunctionalKeyEvent()) {
- handleFunctionalEvent(inputTransaction, currentKeyboardScriptId, handler);
- } else {
- handleNonFunctionalEvent(inputTransaction, handler);
+ Event currentEvent = processedEvent;
+ while (null != currentEvent) {
+ if (currentEvent.isConsumed()) {
+ handleConsumedEvent(currentEvent, inputTransaction);
+ } else if (currentEvent.isFunctionalKeyEvent()) {
+ handleFunctionalEvent(currentEvent, inputTransaction, currentKeyboardScriptId,
+ handler);
+ } else {
+ handleNonFunctionalEvent(currentEvent, inputTransaction, handler);
+ }
+ currentEvent = currentEvent.mNextEvent;
}
if (!inputTransaction.didAutoCorrect() && processedEvent.mKeyCode != Constants.CODE_SHIFT
&& processedEvent.mKeyCode != Constants.CODE_CAPSLOCK
@@ -584,13 +589,14 @@
* Consumed events represent events that have already been consumed, typically by the
* combining chain.
*
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
*/
- private void handleConsumedEvent(final InputTransaction inputTransaction) {
+ private void handleConsumedEvent(final Event event, final InputTransaction inputTransaction) {
// A consumed event may have text to commit and an update to the composing state, so
// we evaluate both. With some combiners, it's possible than an event contains both
// and we enter both of the following if clauses.
- final CharSequence textToCommit = inputTransaction.mEvent.getTextToCommit();
+ final CharSequence textToCommit = event.getTextToCommit();
if (!TextUtils.isEmpty(textToCommit)) {
mConnection.commitText(textToCommit, 1);
inputTransaction.setDidAffectContents();
@@ -611,15 +617,15 @@
* manage keyboard-related stuff like shift, language switch, settings, layout switch, or
* any key that results in multiple code points like the ".com" key.
*
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
*/
- private void handleFunctionalEvent(final InputTransaction inputTransaction,
+ private void handleFunctionalEvent(final Event event, final InputTransaction inputTransaction,
// TODO: remove these arguments
final int currentKeyboardScriptId, final LatinIME.UIHandler handler) {
- final Event event = inputTransaction.mEvent;
switch (event.mKeyCode) {
case Constants.CODE_DELETE:
- handleBackspace(inputTransaction, currentKeyboardScriptId);
+ handleBackspaceEvent(event, inputTransaction, currentKeyboardScriptId);
// Backspace is a functional key, but it affects the contents of the editor.
inputTransaction.setDidAffectContents();
break;
@@ -670,11 +676,7 @@
// TODO: remove this object
final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER,
event.mKeyCode, event.mX, event.mY, event.isKeyRepeat());
- final InputTransaction tmpTransaction = new InputTransaction(
- inputTransaction.mSettingsValues, tmpEvent,
- inputTransaction.mTimestamp, inputTransaction.mSpaceState,
- inputTransaction.mShiftState);
- handleNonSpecialCharacter(tmpTransaction, handler);
+ handleNonSpecialCharacterEvent(tmpEvent, inputTransaction, handler);
// Shift + Enter is treated as a functional key but it results in adding a new
// line, so that does affect the contents of the editor.
inputTransaction.setDidAffectContents();
@@ -690,12 +692,13 @@
* These events are generally events that cause input, but in some cases they may do other
* things like trigger an editor action.
*
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
*/
- private void handleNonFunctionalEvent(final InputTransaction inputTransaction,
+ private void handleNonFunctionalEvent(final Event event,
+ final InputTransaction inputTransaction,
// TODO: remove this argument
final LatinIME.UIHandler handler) {
- final Event event = inputTransaction.mEvent;
inputTransaction.setDidAffectContents();
switch (event.mCodePoint) {
case Constants.CODE_ENTER:
@@ -718,11 +721,11 @@
} else {
// No action label, and the action from imeOptions is NONE: this is a regular
// enter key that should input a carriage return.
- handleNonSpecialCharacter(inputTransaction, handler);
+ handleNonSpecialCharacterEvent(event, inputTransaction, handler);
}
break;
default:
- handleNonSpecialCharacter(inputTransaction, handler);
+ handleNonSpecialCharacterEvent(event, inputTransaction, handler);
break;
}
}
@@ -735,16 +738,18 @@
* manage keyboard-related stuff like shift, language switch, settings, layout switch, or
* any key that results in multiple code points like the ".com" key.
*
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
*/
- private void handleNonSpecialCharacter(final InputTransaction inputTransaction,
+ private void handleNonSpecialCharacterEvent(final Event event,
+ final InputTransaction inputTransaction,
// TODO: remove this argument
final LatinIME.UIHandler handler) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
+ final int codePoint = event.mCodePoint;
mSpaceState = SpaceState.NONE;
if (inputTransaction.mSettingsValues.isWordSeparator(codePoint)
|| Character.getType(codePoint) == Character.OTHER_SYMBOL) {
- handleSeparator(inputTransaction, handler);
+ handleSeparatorEvent(event, inputTransaction, handler);
} else {
if (SpaceState.PHANTOM == inputTransaction.mSpaceState) {
if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
@@ -756,21 +761,23 @@
commitTyped(inputTransaction.mSettingsValues, LastComposedWord.NOT_A_SEPARATOR);
}
}
- handleNonSeparator(inputTransaction.mSettingsValues, inputTransaction);
+ handleNonSeparatorEvent(event, inputTransaction.mSettingsValues, inputTransaction);
}
}
/**
* Handle a non-separator.
+ * @param event The event to handle.
* @param settingsValues The current settings values.
* @param inputTransaction The transaction in progress.
*/
- private void handleNonSeparator(final SettingsValues settingsValues,
+ private void handleNonSeparatorEvent(final Event event, final SettingsValues settingsValues,
final InputTransaction inputTransaction) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
+ final int codePoint = event.mCodePoint;
// TODO: refactor this method to stop flipping isComposingWord around all the time, and
- // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter
- // which has the same name as other handle* methods but is not the same.
+ // make it shorter (possibly cut into several pieces). Also factor
+ // handleNonSpecialCharacterEvent which has the same name as other handle* methods but is
+ // not the same.
boolean isComposingWord = mWordComposer.isComposingWord();
// TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead.
@@ -817,7 +824,7 @@
resetComposingState(false /* alsoResetLastComposedWord */);
}
if (isComposingWord) {
- mWordComposer.applyProcessedEvent(inputTransaction.mEvent);
+ mWordComposer.applyProcessedEvent(event);
// If it's the first letter, make note of auto-caps state
if (mWordComposer.isSingleLetter()) {
mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState);
@@ -825,10 +832,10 @@
mConnection.setComposingText(getTextWithUnderline(
mWordComposer.getTypedWord()), 1);
} else {
- final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(
+ final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(event,
inputTransaction);
- if (swapWeakSpace && trySwapSwapperAndSpace(inputTransaction)) {
+ if (swapWeakSpace && trySwapSwapperAndSpace(event, inputTransaction)) {
mSpaceState = SpaceState.WEAK;
} else {
sendKeyCodePoint(settingsValues, codePoint);
@@ -841,12 +848,13 @@
/**
* Handle input of a separator code point.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
*/
- private void handleSeparator(final InputTransaction inputTransaction,
+ private void handleSeparatorEvent(final Event event, final InputTransaction inputTransaction,
// TODO: remove this argument
final LatinIME.UIHandler handler) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
+ final int codePoint = event.mCodePoint;
final SettingsValues settingsValues = inputTransaction.mSettingsValues;
final boolean wasComposingWord = mWordComposer.isComposingWord();
// We avoid sending spaces in languages without spaces if we were composing.
@@ -872,7 +880,7 @@
}
}
- final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(
+ final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(event,
inputTransaction);
final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint
@@ -897,10 +905,10 @@
promotePhantomSpace(settingsValues);
}
- if (tryPerformDoubleSpacePeriod(inputTransaction)) {
+ if (tryPerformDoubleSpacePeriod(event, inputTransaction)) {
mSpaceState = SpaceState.DOUBLE;
inputTransaction.setRequiresUpdateSuggestions();
- } else if (swapWeakSpace && trySwapSwapperAndSpace(inputTransaction)) {
+ } else if (swapWeakSpace && trySwapSwapperAndSpace(event, inputTransaction)) {
mSpaceState = SpaceState.SWAP_PUNCTUATION;
mSuggestionStripViewAccessor.setNeutralSuggestionStrip();
} else if (Constants.CODE_SPACE == codePoint) {
@@ -947,12 +955,12 @@
/**
* Handle a press on the backspace key.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
*/
- private void handleBackspace(final InputTransaction inputTransaction,
+ private void handleBackspaceEvent(final Event event, final InputTransaction inputTransaction,
// TODO: remove this argument, put it into settingsValues
final int currentKeyboardScriptId) {
- final Event event = inputTransaction.mEvent;
mSpaceState = SpaceState.NONE;
mDeleteCount++;
@@ -1103,16 +1111,18 @@
*
* This method will check that there are two characters before the cursor and that the first
* one is a space before it does the actual swapping.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
* @return true if the swap has been performed, false if it was prevented by preliminary checks.
*/
- private boolean trySwapSwapperAndSpace(final InputTransaction inputTransaction) {
+ private boolean trySwapSwapperAndSpace(final Event event,
+ final InputTransaction inputTransaction) {
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
if (Constants.CODE_SPACE != codePointBeforeCursor) {
return false;
}
mConnection.deleteSurroundingText(1, 0);
- final String text = inputTransaction.mEvent.getTextToCommit() + " ";
+ final String text = event.getTextToCommit() + " ";
mConnection.commitText(text, 1);
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
return true;
@@ -1120,13 +1130,14 @@
/*
* Strip a trailing space if necessary and returns whether it's a swap weak space situation.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
* @return whether we should swap the space instead of removing it.
*/
- private boolean tryStripSpaceAndReturnWhetherShouldSwapInstead(
+ private boolean tryStripSpaceAndReturnWhetherShouldSwapInstead(final Event event,
final InputTransaction inputTransaction) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
- final boolean isFromSuggestionStrip = inputTransaction.mEvent.isSuggestionStripPress();
+ final int codePoint = event.mCodePoint;
+ final boolean isFromSuggestionStrip = event.isSuggestionStripPress();
if (Constants.CODE_ENTER == codePoint &&
SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) {
mConnection.removeTrailingSpace();
@@ -1171,14 +1182,16 @@
* these conditions are fulfilled, this method applies the transformation and returns true.
* Otherwise, it does nothing and returns false.
*
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
* @return true if we applied the double-space-to-period transformation, false otherwise.
*/
- private boolean tryPerformDoubleSpacePeriod(final InputTransaction inputTransaction) {
+ private boolean tryPerformDoubleSpacePeriod(final Event event,
+ final InputTransaction inputTransaction) {
// Check the setting, the typed character and the countdown. If any of the conditions is
// not fulfilled, return false.
if (!inputTransaction.mSettingsValues.mUseDoubleSpacePeriod
- || Constants.CODE_SPACE != inputTransaction.mEvent.mCodePoint
+ || Constants.CODE_SPACE != event.mCodePoint
|| !isDoubleSpacePeriodCountdownActive(inputTransaction)) {
return false;
}
@@ -1424,6 +1437,7 @@
mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
mWordComposer.setCursorPositionWithinWord(
typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
+ mConnection.maybeMoveTheCursorAroundAndRestoreToWorkaroundABug();
mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor());
if (suggestions.size() <= (shouldIncludeResumedWordInSuggestions ? 1 : 0)) {
@@ -2021,7 +2035,7 @@
mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(),
shouldFinishComposition)) {
if (0 < remainingTries) {
- handler.postResetCaches(tryResumeSuggestions, remainingTries - 1);
+ handler.postResetInputConnectionCaches(tryResumeSuggestions, remainingTries - 1);
return false;
}
// If remainingTries is 0, we should stop waiting for new tries, however we'll still
diff --git a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
index 21f2afd..6d7f53c 100644
--- a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
@@ -63,7 +63,6 @@
private AlertDialog mSubtypeEnablerNotificationDialog;
private String mSubtypePreferenceKeyForSubtypeEnabler;
- private static final int MENU_ADD_SUBTYPE = Menu.FIRST;
private static final String KEY_IS_ADDING_NEW_SUBTYPE = "is_adding_new_subtype";
private static final String KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN =
"is_subtype_enabler_notification_dialog_open";
@@ -581,14 +580,13 @@
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
- final MenuItem addSubtypeMenu = menu.add(0, MENU_ADD_SUBTYPE, 0, R.string.add_style);
- addSubtypeMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ inflater.inflate(R.menu.add_style, menu);
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int itemId = item.getItemId();
- if (itemId == MENU_ADD_SUBTYPE) {
+ if (itemId == R.id.action_add_style) {
final SubtypePreference newSubtype =
SubtypePreference.newIncompleteSubtypePreference(getActivity(), mSubtypeProxy);
getPreferenceScreen().addPreference(newSubtype);
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 4220a95..278f2b1 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
@@ -231,30 +231,31 @@
&probabilityEntryToWrite);
}
-bool Ver4PatriciaTrieNodeWriter::addNewBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam,
- const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
- if (!mBigramPolicy->addNewEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId(), bigramProperty, outAddedNewBigram)) {
+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());
return false;
}
- if (!sourcePtNodeParams->hasBigrams()) {
+ const int ptNodePos =
+ mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(prevWordIds[0]);
+ const PtNodeParams sourcePtNodeParams =
+ mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos);
+ if (!sourcePtNodeParams.hasBigrams()) {
// Update has bigrams flag.
- return updatePtNodeFlags(sourcePtNodeParams->getHeadPos(),
- sourcePtNodeParams->isBlacklisted(), sourcePtNodeParams->isNotAWord(),
- sourcePtNodeParams->isTerminal(), sourcePtNodeParams->hasShortcutTargets(),
+ return updatePtNodeFlags(sourcePtNodeParams.getHeadPos(),
+ sourcePtNodeParams.isBlacklisted(), sourcePtNodeParams.isNotAWord(),
+ sourcePtNodeParams.isTerminal(), sourcePtNodeParams.hasShortcutTargets(),
true /* hasBigrams */,
- sourcePtNodeParams->getCodePointCount() > 1 /* hasMultipleChars */);
+ sourcePtNodeParams.getCodePointCount() > 1 /* hasMultipleChars */);
}
return true;
}
-bool Ver4PatriciaTrieNodeWriter::removeBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam) {
- return mBigramPolicy->removeEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId());
+bool Ver4PatriciaTrieNodeWriter::removeNgramEntry(const WordIdArrayView prevWordIds,
+ const int wordId) {
+ return mBigramPolicy->removeEntry(prevWordIds[0], wordId);
}
bool Ver4PatriciaTrieNodeWriter::updateAllBigramEntriesAndDeleteUselessEntries(
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
index 08226ea..d49d9a6 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
@@ -29,6 +29,7 @@
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h"
#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h"
+#include "utils/int_array_view.h"
namespace latinime {
namespace backward {
@@ -61,8 +62,8 @@
const PtNodeArrayReader *const ptNodeArrayReader,
Ver4BigramListPolicy *const bigramPolicy, Ver4ShortcutListPolicy *const shortcutPolicy)
: mTrieBuffer(trieBuffer), mBuffers(buffers), mHeaderPolicy(headerPolicy),
- mReadingHelper(ptNodeReader, ptNodeArrayReader), mBigramPolicy(bigramPolicy),
- mShortcutPolicy(shortcutPolicy) {}
+ mPtNodeReader(ptNodeReader), mReadingHelper(ptNodeReader, ptNodeArrayReader),
+ mBigramPolicy(bigramPolicy), mShortcutPolicy(shortcutPolicy) {}
virtual ~Ver4PatriciaTrieNodeWriter() {}
@@ -92,12 +93,10 @@
virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams,
const UnigramProperty *const unigramProperty, int *const ptNodeWritingPos);
- virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam, const BigramProperty *const bigramProperty,
- bool *const outAddedNewBigram);
+ virtual bool addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
- virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam);
+ virtual bool removeNgramEntry(const WordIdArrayView prevWordIds, const int wordId);
virtual bool updateAllBigramEntriesAndDeleteUselessEntries(
const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount);
@@ -135,6 +134,7 @@
BufferWithExtendableBuffer *const mTrieBuffer;
Ver4DictBuffers *const mBuffers;
const HeaderPolicy *const mHeaderPolicy;
+ const PtNodeReader *const mPtNodeReader;
DynamicPtReadingHelper mReadingHelper;
Ver4BigramListPolicy *const mBigramPolicy;
Ver4ShortcutListPolicy *const mShortcutPolicy;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
index baa0c0c..1296b8a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
@@ -309,8 +309,8 @@
return false;
}
bool addedNewBigram = false;
- if (mUpdatingHelper.addBigramWords(prevWordsPtNodePos[0], word1Pos, bigramProperty,
- &addedNewBigram)) {
+ if (mUpdatingHelper.addNgramEntry(PtNodePosArrayView::fromObject(prevWordsPtNodePos),
+ word1Pos, bigramProperty, &addedNewBigram)) {
if (addedNewBigram) {
mBigramCount++;
}
@@ -350,7 +350,8 @@
if (wordPos == NOT_A_DICT_POS) {
return false;
}
- if (mUpdatingHelper.removeBigramWords(prevWordsPtNodePos[0], wordPos)) {
+ if (mUpdatingHelper.removeNgramEntry(
+ PtNodePosArrayView::fromObject(prevWordsPtNodePos), wordPos)) {
mBigramCount--;
return true;
} else {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
index f31c914..3c62e2e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
@@ -84,23 +84,39 @@
unigramProperty, &pos);
}
-bool DynamicPtUpdatingHelper::addBigramWords(const int word0Pos, const int word1Pos,
- const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
- const PtNodeParams sourcePtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word0Pos));
- const PtNodeParams targetPtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word1Pos));
- return mPtNodeWriter->addNewBigramEntry(&sourcePtNodeParams, &targetPtNodeParams,
- bigramProperty, outAddedNewBigram);
+bool DynamicPtUpdatingHelper::addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos,
+ const int wordPos, const BigramProperty *const bigramProperty,
+ bool *const outAddedNewEntry) {
+ if (prevWordsPtNodePos.empty()) {
+ return false;
+ }
+ ASSERT(prevWordsPtNodePos.size() <= MAX_PREV_WORD_COUNT_FOR_N_GRAM);
+ int prevWordTerminalIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+ for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
+ prevWordTerminalIds[i] = mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(
+ prevWordsPtNodePos[i]).getTerminalId();
+ }
+ const WordIdArrayView prevWordIds(prevWordTerminalIds, prevWordsPtNodePos.size());
+ const int wordId =
+ mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(wordPos).getTerminalId();
+ return mPtNodeWriter->addNgramEntry(prevWordIds, wordId, bigramProperty, outAddedNewEntry);
}
-// Remove a bigram relation from word0Pos to word1Pos.
-bool DynamicPtUpdatingHelper::removeBigramWords(const int word0Pos, const int word1Pos) {
- const PtNodeParams sourcePtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word0Pos));
- const PtNodeParams targetPtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word1Pos));
- return mPtNodeWriter->removeBigramEntry(&sourcePtNodeParams, &targetPtNodeParams);
+bool DynamicPtUpdatingHelper::removeNgramEntry(const PtNodePosArrayView prevWordsPtNodePos,
+ const int wordPos) {
+ if (prevWordsPtNodePos.empty()) {
+ return false;
+ }
+ ASSERT(prevWordsPtNodePos.size() <= MAX_PREV_WORD_COUNT_FOR_N_GRAM);
+ int prevWordTerminalIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+ for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
+ prevWordTerminalIds[i] = mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(
+ prevWordsPtNodePos[i]).getTerminalId();
+ }
+ const WordIdArrayView prevWordIds(prevWordTerminalIds, prevWordsPtNodePos.size());
+ const int wordId =
+ mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(wordPos).getTerminalId();
+ return mPtNodeWriter->removeNgramEntry(prevWordIds, wordId);
}
bool DynamicPtUpdatingHelper::addShortcutTarget(const int wordPos,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
index f10d15a..97c05c1 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
@@ -19,6 +19,7 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
+#include "utils/int_array_view.h"
namespace latinime {
@@ -42,12 +43,12 @@
const int *const wordCodePoints, const int codePointCount,
const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram);
- // Add a bigram relation from word0Pos to word1Pos.
- bool addBigramWords(const int word0Pos, const int word1Pos,
- const BigramProperty *const bigramProperty, bool *const outAddedNewBigram);
+ // Add an n-gram entry.
+ bool addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
- // Remove a bigram relation from word0Pos to word1Pos.
- bool removeBigramWords(const int word0Pos, const int word1Pos);
+ // Remove an n-gram entry.
+ bool removeNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos);
// Add a shortcut target.
bool addShortcutTarget(const int wordPos, const int *const targetCodePoints,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h
index a8029f7..955d779 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h
@@ -21,6 +21,7 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
+#include "utils/int_array_view.h"
namespace latinime {
@@ -70,12 +71,10 @@
virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams,
const UnigramProperty *const unigramProperty, int *const ptNodeWritingPos) = 0;
- virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam, const BigramProperty *const bigramProperty,
- bool *const outAddedNewBigram) = 0;
+ virtual bool addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry) = 0;
- virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam) = 0;
+ virtual bool removeNgramEntry(const WordIdArrayView prevWordIds, const int wordId) = 0;
virtual bool updateAllBigramEntriesAndDeleteUselessEntries(
const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount) = 0;
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 07e1051..5dc91ba 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
@@ -32,11 +32,11 @@
ProbabilityEntry LanguageModelDictContent::getNgramProbabilityEntry(
const WordIdArrayView prevWordIds, const int wordId) const {
- if (!prevWordIds.empty()) {
- // TODO: Read n-gram entry.
+ const int bitmapEntryIndex = getBitmapEntryIndex(prevWordIds);
+ if (bitmapEntryIndex == TrieMap::INVALID_INDEX) {
return ProbabilityEntry();
}
- const TrieMap::Result result = mTrieMap.getRoot(wordId);
+ const TrieMap::Result result = mTrieMap.get(wordId, bitmapEntryIndex);
if (!result.mIsValid) {
// Not found.
return ProbabilityEntry();
@@ -46,14 +46,13 @@
bool LanguageModelDictContent::setNgramProbabilityEntry(const WordIdArrayView prevWordIds,
const int terminalId, const ProbabilityEntry *const probabilityEntry) {
- if (!prevWordIds.empty()) {
- // TODO: Add n-gram entry.
+ const int bitmapEntryIndex = getBitmapEntryIndex(prevWordIds);
+ if (bitmapEntryIndex == TrieMap::INVALID_INDEX) {
return false;
}
- return mTrieMap.putRoot(terminalId, probabilityEntry->encode(mHasHistoricalInfo));
+ return mTrieMap.put(terminalId, probabilityEntry->encode(mHasHistoricalInfo), bitmapEntryIndex);
}
-
bool LanguageModelDictContent::runGCInner(
const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
const TrieMap::TrieMapRange trieMapRange,
@@ -81,4 +80,16 @@
return true;
}
+int LanguageModelDictContent::getBitmapEntryIndex(const WordIdArrayView prevWordIds) const {
+ int bitmapEntryIndex = mTrieMap.getRootBitmapEntryIndex();
+ for (const int wordId : prevWordIds) {
+ const TrieMap::Result result = mTrieMap.get(wordId, bitmapEntryIndex);
+ if (!result.mIsValid) {
+ return TrieMap::INVALID_INDEX;
+ }
+ bitmapEntryIndex = result.mNextLevelBitmapEntryIndex;
+ }
+ return bitmapEntryIndex;
+}
+
} // namespace latinime
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 f181dfe..18f2e01 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,6 +76,8 @@
bool runGCInner(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
const TrieMap::TrieMapRange trieMapRange, const int nextLevelBitmapEntryIndex,
int *const outNgramCount);
+
+ int getBitmapEntryIndex(const WordIdArrayView prevWordIds) const;
};
} // namespace latinime
#endif /* LATINIME_LANGUAGE_MODEL_DICT_CONTENT_H */
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 1a311b1..857222f 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
@@ -222,22 +222,19 @@
terminalId, &probabilityEntryToWrite);
}
-bool Ver4PatriciaTrieNodeWriter::addNewBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam,
+bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
- if (!mBigramPolicy->addNewEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId(), bigramProperty, outAddedNewBigram)) {
+ if (!mBigramPolicy->addNewEntry(prevWordIds[0], wordId, bigramProperty, outAddedNewBigram)) {
AKLOGE("Cannot add new bigram entry. terminalId: %d, targetTerminalId: %d",
- sourcePtNodeParams->getTerminalId(), targetPtNodeParam->getTerminalId());
+ prevWordIds[0], wordId);
return false;
}
return true;
}
-bool Ver4PatriciaTrieNodeWriter::removeBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam) {
- return mBigramPolicy->removeEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId());
+bool Ver4PatriciaTrieNodeWriter::removeNgramEntry(const WordIdArrayView prevWordIds,
+ const int wordId) {
+ return mBigramPolicy->removeEntry(prevWordIds[0], wordId);
}
bool Ver4PatriciaTrieNodeWriter::updateAllBigramEntriesAndDeleteUselessEntries(
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 162dc9b..6703dba 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
@@ -75,12 +75,10 @@
virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams,
const UnigramProperty *const unigramProperty, int *const ptNodeWritingPos);
- virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam, const BigramProperty *const bigramProperty,
- bool *const outAddedNewBigram);
+ virtual bool addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
- virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam);
+ virtual bool removeNgramEntry(const WordIdArrayView prevWordIds, const int wordId);
virtual bool updateAllBigramEntriesAndDeleteUselessEntries(
const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index 2b92d5b..7238083 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -292,6 +292,7 @@
int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos,
false /* tryLowerCaseSearch */);
+ const auto prevWordsPtNodePosView = PtNodePosArrayView::fromFixedSizeArray(prevWordsPtNodePos);
// TODO: Support N-gram.
if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) {
@@ -319,10 +320,10 @@
if (word1Pos == NOT_A_DICT_POS) {
return false;
}
- bool addedNewBigram = false;
- if (mUpdatingHelper.addBigramWords(prevWordsPtNodePos[0], word1Pos, bigramProperty,
- &addedNewBigram)) {
- if (addedNewBigram) {
+ bool addedNewEntry = false;
+ if (mUpdatingHelper.addNgramEntry(prevWordsPtNodePosView, word1Pos, bigramProperty,
+ &addedNewEntry)) {
+ if (addedNewEntry) {
mBigramCount++;
}
return true;
@@ -352,6 +353,7 @@
int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos,
false /* tryLowerCaseSerch */);
+ const auto prevWordsPtNodePosView = PtNodePosArrayView::fromFixedSizeArray(prevWordsPtNodePos);
// TODO: Support N-gram.
if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
return false;
@@ -361,7 +363,7 @@
if (wordPos == NOT_A_DICT_POS) {
return false;
}
- if (mUpdatingHelper.removeBigramWords(prevWordsPtNodePos[0], wordPos)) {
+ if (mUpdatingHelper.removeNgramEntry(prevWordsPtNodePosView, wordPos)) {
mBigramCount--;
return true;
} else {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
index a294ab8..3e5c401 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
@@ -169,6 +169,10 @@
return mBuffer.isNearSizeLimit();
}
+ int getRootBitmapEntryIndex() const {
+ return ROOT_BITMAP_ENTRY_INDEX;
+ }
+
// Returns bitmapEntryIndex. Create the next level map if it doesn't exist.
int getNextLevelBitmapEntryIndex(const int key) {
return getNextLevelBitmapEntryIndex(key, ROOT_BITMAP_ENTRY_INDEX);
diff --git a/native/jni/src/utils/int_array_view.h b/native/jni/src/utils/int_array_view.h
index 4bc2487..c1ddc98 100644
--- a/native/jni/src/utils/int_array_view.h
+++ b/native/jni/src/utils/int_array_view.h
@@ -56,6 +56,16 @@
explicit IntArrayView(const std::vector<int> &vector)
: mPtr(vector.data()), mSize(vector.size()) {}
+ template <int N>
+ AK_FORCE_INLINE static IntArrayView fromFixedSizeArray(const int (&array)[N]) {
+ return IntArrayView(array, N);
+ }
+
+ // Returns a view that points one int object. Does not take ownership of the given object.
+ AK_FORCE_INLINE static IntArrayView fromObject(const int *const object) {
+ return IntArrayView(object, 1);
+ }
+
AK_FORCE_INLINE int operator[](const size_t index) const {
ASSERT(index < mSize);
return mPtr[index];
@@ -73,6 +83,14 @@
return mPtr;
}
+ AK_FORCE_INLINE const int *begin() const {
+ return mPtr;
+ }
+
+ AK_FORCE_INLINE const int *end() const {
+ return mPtr + mSize;
+ }
+
private:
DISALLOW_ASSIGNMENT_OPERATOR(IntArrayView);
@@ -81,6 +99,7 @@
};
using WordIdArrayView = IntArrayView;
+using PtNodePosArrayView = IntArrayView;
} // namespace latinime
#endif // LATINIME_MEMORY_VIEW_H
diff --git a/native/jni/tests/utils/int_array_view_test.cpp b/native/jni/tests/utils/int_array_view_test.cpp
index 9aa8cdc..bd843ab 100644
--- a/native/jni/tests/utils/int_array_view_test.cpp
+++ b/native/jni/tests/utils/int_array_view_test.cpp
@@ -23,16 +23,39 @@
namespace latinime {
namespace {
-TEST(MemoryViewTest, TestAccess) {
- static const int DATA_SIZE = 10000;
-
- std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+TEST(IntArrayViewTest, TestAccess) {
+ const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
IntArrayView intArrayView(intVector);
EXPECT_EQ(intVector.size(), intArrayView.size());
- for (int i = 0; i < DATA_SIZE; ++i) {
+ for (int i = 0; i < static_cast<int>(intVector.size()); ++i) {
EXPECT_EQ(intVector[i], intArrayView[i]);
}
}
+TEST(IntArrayViewTest, TestIteration) {
+ const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+ IntArrayView intArrayView(intVector);
+ size_t expectedIndex = 0;
+ for (const int element : intArrayView) {
+ EXPECT_EQ(intVector[expectedIndex], element);
+ ++expectedIndex;
+ }
+ EXPECT_EQ(expectedIndex, intArrayView.size());
+}
+
+TEST(IntArrayViewTest, TestConstructFromArray) {
+ const size_t ARRAY_SIZE = 100;
+ int intArray[ARRAY_SIZE];
+ const auto intArrayView = IntArrayView::fromFixedSizeArray(intArray);
+ EXPECT_EQ(ARRAY_SIZE, intArrayView.size());
+}
+
+TEST(IntArrayViewTest, TestConstructFromObject) {
+ const int object = 10;
+ const auto intArrayView = IntArrayView::fromObject(&object);
+ EXPECT_EQ(1, intArrayView.size());
+ EXPECT_EQ(object, intArrayView[0]);
+}
+
} // namespace
} // namespace latinime