aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/utils
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/utils')
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java71
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java (renamed from java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java)6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CollectionUtils.java5
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java10
-rw-r--r--java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java108
-rw-r--r--java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java147
-rw-r--r--java/src/com/android/inputmethod/latin/utils/StringUtils.java82
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java1
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java47
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java12
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java4
12 files changed, 351 insertions, 148 deletions
diff --git a/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java
new file mode 100644
index 000000000..c2e97a36f
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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.utils;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class is a holder of a result of asynchronous computation.
+ *
+ * @param <E> the type of the result.
+ */
+public class AsyncResultHolder<E> {
+
+ private final Object mLock = new Object();
+
+ private E mResult;
+ private final CountDownLatch mLatch;
+
+ public AsyncResultHolder() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ /**
+ * Sets the result value to this holder.
+ *
+ * @param result the value which is set.
+ */
+ public void set(final E result) {
+ synchronized(mLock) {
+ if (mLatch.getCount() > 0) {
+ mResult = result;
+ mLatch.countDown();
+ }
+ }
+ }
+
+ /**
+ * Gets the result value held in this holder.
+ * Causes the current thread to wait unless the value is set or the specified time is elapsed.
+ *
+ * @param defaultValue the default value.
+ * @param timeOut the time to wait.
+ * @return if the result is set until the time limit then the result, otherwise defaultValue.
+ */
+ public E get(final E defaultValue, final long timeOut) {
+ try {
+ if(mLatch.await(timeOut, TimeUnit.MILLISECONDS)) {
+ return mResult;
+ } else {
+ return defaultValue;
+ }
+ } catch (InterruptedException e) {
+ return defaultValue;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java b/java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java
index 1bb27aa2b..2028298f2 100644
--- a/java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java
+++ b/java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java
@@ -16,17 +16,17 @@
package com.android.inputmethod.latin.utils;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
/**
* This class provides an implementation for the FusionDictionary buffer interface that is backed
* by a simpled byte array. It allows to create a binary dictionary in memory.
*/
-public final class ByteArrayWrapper implements FusionDictionaryBufferInterface {
+public final class ByteArrayDictBuffer implements DictBuffer {
private byte[] mBuffer;
private int mPosition;
- public ByteArrayWrapper(final byte[] buffer) {
+ public ByteArrayDictBuffer(final byte[] buffer) {
mBuffer = buffer;
mPosition = 0;
}
diff --git a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
index 98f0d8b68..cc25102ce 100644
--- a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin.utils;
import android.util.SparseArray;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -94,6 +95,10 @@ public final class CollectionUtils {
return new CopyOnWriteArrayList<E>(array);
}
+ public static <E> ArrayDeque<E> newArrayDeque() {
+ return new ArrayDeque<E>();
+ }
+
public static <E> SparseArray<E> newSparseArray() {
return new SparseArray<E>();
}
diff --git a/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java b/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
index c4ead0ad1..ac654fa65 100644
--- a/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
@@ -65,12 +65,12 @@ public final class DebugLogUtils {
/**
* Get the stack trace contained in an exception as a human-readable string.
- * @param e the exception
+ * @param t the throwable
* @return the human-readable stack trace
*/
- public static String getStackTrace(final Exception e) {
+ public static String getStackTrace(final Throwable t) {
final StringBuilder sb = new StringBuilder();
- final StackTraceElement[] frames = e.getStackTrace();
+ final StackTraceElement[] frames = t.getStackTrace();
for (int j = 0; j < frames.length; ++j) {
sb.append(frames[j].toString() + "\n");
}
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 34eccd65b..021bf0825 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -27,10 +27,8 @@ import com.android.inputmethod.latin.BinaryDictionaryGetter;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
-import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
@@ -281,13 +279,7 @@ public class DictionaryInfoUtils {
}
public static FileHeader getDictionaryFileHeaderOrNull(final File file) {
- try {
- return BinaryDictIOUtils.getDictionaryFileHeader(file, 0, file.length());
- } catch (UnsupportedFormatException e) {
- return null;
- } catch (IOException e) {
- return null;
- }
+ return BinaryDictIOUtils.getDictionaryFileHeaderOrNull(file, 0, file.length());
}
private static DictionaryInfo createDictionaryInfoFromFileAddress(
diff --git a/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java
deleted file mode 100644
index 1fc7eccc6..000000000
--- a/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2012 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.utils;
-
-import android.view.inputmethod.EditorInfo;
-
-import com.android.inputmethod.latin.RichInputConnection;
-
-import java.util.Locale;
-
-/**
- * Holder class for data about a word already committed but that may still be edited.
- *
- * When the user chooses to add a word to the user dictionary by pressing the appropriate
- * suggestion, a dialog is presented to give a chance to edit the word before it is actually
- * registered as a user dictionary word. If the word is actually modified, the IME needs to
- * go back and replace the word that was committed with the amended version.
- * The word we need to replace with will only be known after it's actually committed, so
- * the IME needs to take a note of what it has to replace and where it is.
- * This class encapsulates this data.
- */
-public final class PositionalInfoForUserDictPendingAddition {
- final private String mOriginalWord;
- final private int mCursorPos; // Position of the cursor after the word
- final private EditorInfo mEditorInfo; // On what binding this has been added
- final private int mCapitalizedMode;
- private String mActualWordBeingAdded;
-
- public PositionalInfoForUserDictPendingAddition(final String word, final int cursorPos,
- final EditorInfo editorInfo, final int capitalizedMode) {
- mOriginalWord = word;
- mCursorPos = cursorPos;
- mEditorInfo = editorInfo;
- mCapitalizedMode = capitalizedMode;
- }
-
- public void setActualWordBeingAdded(final String actualWordBeingAdded) {
- mActualWordBeingAdded = actualWordBeingAdded;
- }
-
- /**
- * Try to replace the string at the remembered position with the actual word being added.
- *
- * After the user validated the word being added, the IME has to replace the old version
- * (which has been committed in the text view) with the amended version if it's different.
- * This method tries to do that, but may fail because the IME is not yet ready to do so -
- * for example, it is still waiting for the new string, or it is waiting to return to the text
- * view in which the amendment should be made. In these cases, we should keep the data
- * and wait until all conditions are met.
- * This method returns true if the replacement has been successfully made and this data
- * can be forgotten; it returns false if the replacement can't be made yet and we need to
- * keep this until a later time.
- * The IME knows about the actual word being added through a callback called by the
- * user dictionary facility of the device. When this callback comes, the keyboard may still
- * be connected to the edition dialog, or it may have already returned to the original text
- * field. Replacement has to work in both cases.
- * Accordingly, this method is called at two different points in time : upon getting the
- * event that a new word was added to the user dictionary, and upon starting up in a
- * new text field.
- * @param connection The RichInputConnection through which to contact the editor.
- * @param editorInfo Information pertaining to the editor we are currently in.
- * @param currentCursorPosition The current cursor position, for checking purposes.
- * @param locale The locale for changing case, if necessary
- * @return true if the edit has been successfully made, false if we need to try again later
- */
- public boolean tryReplaceWithActualWord(final RichInputConnection connection,
- final EditorInfo editorInfo, final int currentCursorPosition, final Locale locale) {
- // If we still don't know the actual word being added, we need to try again later.
- if (null == mActualWordBeingAdded) return false;
- // The entered text and the registered text were the same anyway : we can
- // return success right away even if focus has not returned yet to the text field we
- // want to amend.
- if (mActualWordBeingAdded.equals(mOriginalWord)) return true;
- // Not the same text field : we need to try again later. This happens when the addition
- // is reported by the user dictionary provider before the focus has moved back to the
- // original text view, so the IME is still in the text view of the dialog and has no way to
- // edit the original text view at this time.
- if (!mEditorInfo.packageName.equals(editorInfo.packageName)
- || mEditorInfo.fieldId != editorInfo.fieldId) {
- return false;
- }
- // Same text field, but not the same cursor position : we give up, so we return success
- // so that it won't be tried again
- if (currentCursorPosition != mCursorPos) return true;
- // We have made all the checks : do the replacement and report success
- // If this was auto-capitalized, we need to restore the case before committing
- final String wordWithCaseFixed = CapsModeUtils.applyAutoCapsMode(mActualWordBeingAdded,
- mCapitalizedMode, locale);
- connection.setComposingRegion(currentCursorPosition - mOriginalWord.length(),
- currentCursorPosition);
- connection.commitText(wordWithCaseFixed, wordWithCaseFixed.length());
- return true;
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
new file mode 100644
index 000000000..5dc0b5893
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2013 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.utils;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * An object that executes submitted tasks using a thread.
+ */
+public class PrioritizedSerialExecutor {
+ public static final String TAG = PrioritizedSerialExecutor.class.getSimpleName();
+
+ private final Object mLock = new Object();
+
+ // The default value of capacities of task queues.
+ private static final int TASK_QUEUE_CAPACITY = 1000;
+ private final Queue<Runnable> mTasks;
+ private final Queue<Runnable> mPrioritizedTasks;
+ private boolean mIsShutdown;
+
+ // The task which is running now.
+ private Runnable mActive;
+
+ public PrioritizedSerialExecutor() {
+ mTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
+ mPrioritizedTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
+ mIsShutdown = false;
+ }
+
+ /**
+ * Clears all queued tasks.
+ */
+ public void clearAllTasks() {
+ synchronized(mLock) {
+ mTasks.clear();
+ mPrioritizedTasks.clear();
+ }
+ }
+
+ /**
+ * Enqueues the given task into the task queue.
+ * @param r the enqueued task
+ */
+ public void execute(final Runnable r) {
+ synchronized(mLock) {
+ if (!mIsShutdown) {
+ mTasks.offer(r);
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+ }
+ }
+
+ /**
+ * Enqueues the given task into the prioritized task queue.
+ * @param r the enqueued task
+ */
+ public void executePrioritized(final Runnable r) {
+ synchronized(mLock) {
+ if (!mIsShutdown) {
+ mPrioritizedTasks.offer(r);
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+ }
+ }
+
+ private boolean fetchNextTasks() {
+ synchronized(mLock) {
+ mActive = mPrioritizedTasks.poll();
+ if (mActive == null) {
+ mActive = mTasks.poll();
+ }
+ return mActive != null;
+ }
+ }
+
+ private void scheduleNext() {
+ synchronized(mLock) {
+ if (!fetchNextTasks()) {
+ return;
+ }
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ do {
+ synchronized(mLock) {
+ if (mActive != null) {
+ mActive.run();
+ }
+ }
+ } while (fetchNextTasks());
+ } finally {
+ scheduleNext();
+ }
+ }
+ }).start();
+ }
+ }
+
+ public void remove(final Runnable r) {
+ synchronized(mLock) {
+ mTasks.remove(r);
+ mPrioritizedTasks.remove(r);
+ }
+ }
+
+ public void replaceAndExecute(final Runnable oldTask, final Runnable newTask) {
+ synchronized(mLock) {
+ if (oldTask != null) remove(oldTask);
+ execute(newTask);
+ }
+ }
+
+ public void shutdown() {
+ synchronized(mLock) {
+ mIsShutdown = true;
+ }
+ }
+
+ public boolean isTerminated() {
+ synchronized(mLock) {
+ if (!mIsShutdown) {
+ return false;
+ }
+ return mPrioritizedTasks.isEmpty() && mTasks.isEmpty() && mActive == null;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index 7406d855a..be4184093 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -18,7 +18,9 @@ package com.android.inputmethod.latin.utils;
import android.text.TextUtils;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.settings.SettingsValues;
import java.util.ArrayList;
import java.util.Locale;
@@ -193,27 +195,56 @@ public final class StringUtils {
}
public static boolean isIdenticalAfterUpcase(final String text) {
- final int len = text.length();
- for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
+ final int length = text.length();
+ int i = 0;
+ while (i < length) {
final int codePoint = text.codePointAt(i);
if (Character.isLetter(codePoint) && !Character.isUpperCase(codePoint)) {
return false;
}
+ i += Character.charCount(codePoint);
}
return true;
}
public static boolean isIdenticalAfterDowncase(final String text) {
- final int len = text.length();
- for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
+ final int length = text.length();
+ int i = 0;
+ while (i < length) {
final int codePoint = text.codePointAt(i);
if (Character.isLetter(codePoint) && !Character.isLowerCase(codePoint)) {
return false;
}
+ i += Character.charCount(codePoint);
}
return true;
}
+ @UsedForTesting
+ public static boolean looksValidForDictionaryInsertion(final CharSequence text,
+ final SettingsValues settings) {
+ if (TextUtils.isEmpty(text)) return false;
+ final int length = text.length();
+ int i = 0;
+ int digitCount = 0;
+ while (i < length) {
+ final int codePoint = Character.codePointAt(text, i);
+ final int charCount = Character.charCount(codePoint);
+ i += charCount;
+ if (Character.isDigit(codePoint)) {
+ // Count digits: see below
+ digitCount += charCount;
+ continue;
+ }
+ if (!settings.isWordCodePoint(codePoint)) return false;
+ }
+ // We reject strings entirely comprised of digits to avoid using PIN codes or credit
+ // card numbers. It would come in handy for word prediction though; a good example is
+ // when writing one's address where the street number is usually quite discriminative,
+ // as well as the postal code.
+ return digitCount < length;
+ }
+
public static boolean isIdenticalAfterCapitalizeEachWord(final String text,
final String separators) {
boolean needCapsNext = true;
@@ -316,4 +347,47 @@ public final class StringUtils {
// Otherwise, it doesn't look like an URL.
return false;
}
+
+ public static boolean isEmptyStringOrWhiteSpaces(String s) {
+ final int N = codePointCount(s);
+ for (int i = 0; i < N; ++i) {
+ if (!Character.isWhitespace(s.codePointAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @UsedForTesting
+ public static String byteArrayToHexString(byte[] bytes) {
+ if (bytes == null || bytes.length == 0) {
+ return "";
+ }
+ final StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02x", b & 0xff));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convert hex string to byte array. The string length must be an even number.
+ */
+ @UsedForTesting
+ public static byte[] hexStringToByteArray(String hexString) {
+ if (TextUtils.isEmpty(hexString)) {
+ return null;
+ }
+ final int N = hexString.length();
+ if (N % 2 != 0) {
+ throw new NumberFormatException("Input hex string length must be an even number."
+ + " Length = " + N);
+ }
+ final byte[] bytes = new byte[N / 2];
+ for (int i = 0; i < N; i += 2) {
+ bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ + Character.digit(hexString.charAt(i + 1), 16));
+ }
+ return bytes;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 16728092d..102a41b4e 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -40,6 +40,7 @@ public final class SubtypeLocaleUtils {
// Special language code to represent "no language".
public static final String NO_LANGUAGE = "zz";
public static final String QWERTY = "qwerty";
+ public static final String EMOJI = "emoji";
public static final int UNKNOWN_KEYBOARD_LAYOUT = R.string.subtype_generic;
private static boolean sInitialized = false;
diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
index d02f7187e..ea32a74ff 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
@@ -20,20 +20,21 @@ import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
+import com.android.inputmethod.latin.makedict.DictDecoder;
+import com.android.inputmethod.latin.makedict.DictEncoder;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.PendingAttribute;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList;
import java.io.IOException;
-import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
/**
* Reads and writes Binary files for a UserHistoryDictionary.
@@ -43,6 +44,9 @@ import java.util.Map;
public final class UserHistoryDictIOUtils {
private static final String TAG = UserHistoryDictIOUtils.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final String USES_FORGETTING_CURVE_KEY = "USES_FORGETTING_CURVE";
+ private static final String USES_FORGETTING_CURVE_VALUE = "1";
+ private static final String LAST_UPDATED_TIME_KEY = "date";
public interface OnAddWordListener {
public void setUnigram(final String word, final String shortcutTarget, final int frequency);
@@ -57,12 +61,15 @@ public final class UserHistoryDictIOUtils {
/**
* Writes dictionary to file.
*/
- public static void writeDictionaryBinary(final OutputStream destination,
+ public static void writeDictionary(final DictEncoder dictEncoder,
final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams,
final FormatOptions formatOptions) {
final FusionDictionary fusionDict = constructFusionDictionary(dict, bigrams);
+ fusionDict.addOptionAttribute(USES_FORGETTING_CURVE_KEY, USES_FORGETTING_CURVE_VALUE);
+ fusionDict.addOptionAttribute(LAST_UPDATED_TIME_KEY,
+ String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())));
try {
- BinaryDictInputOutput.writeDictionaryBinary(destination, fusionDict, formatOptions);
+ dictEncoder.writeDictionary(fusionDict, formatOptions);
Log.d(TAG, "end writing");
} catch (IOException e) {
Log.e(TAG, "IO exception while writing file", e);
@@ -77,7 +84,7 @@ public final class UserHistoryDictIOUtils {
@UsedForTesting
static FusionDictionary constructFusionDictionary(
final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams) {
- final FusionDictionary fusionDict = new FusionDictionary(new Node(),
+ final FusionDictionary fusionDict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(new HashMap<String, String>(), false,
false));
int profTotal = 0;
@@ -101,7 +108,7 @@ public final class UserHistoryDictIOUtils {
if (word1 == null) { // unigram
fusionDict.add(word2, freq, null, false /* isNotAWord */);
} else { // bigram
- if (FusionDictionary.findWordInTree(fusionDict.mRoot, word1) == null) {
+ if (FusionDictionary.findWordInTree(fusionDict.mRootNodeArray, word1) == null) {
fusionDict.add(word1, 2, null, false /* isNotAWord */);
}
fusionDict.setBigram(word1, word2, freq);
@@ -118,14 +125,13 @@ public final class UserHistoryDictIOUtils {
/**
* Reads dictionary from file.
*/
- public static void readDictionaryBinary(final FusionDictionaryBufferInterface buffer,
+ public static void readDictionaryBinary(final DictDecoder dictDecoder,
final OnAddWordListener dict) {
- final Map<Integer, String> unigrams = CollectionUtils.newTreeMap();
- final Map<Integer, Integer> frequencies = CollectionUtils.newTreeMap();
- final Map<Integer, ArrayList<PendingAttribute>> bigrams = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, String> unigrams = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, Integer> frequencies = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams = CollectionUtils.newTreeMap();
try {
- BinaryDictIOUtils.readUnigramsAndBigramsBinary(buffer, unigrams, frequencies,
- bigrams);
+ dictDecoder.readUnigramsAndBigramsBinary(unigrams, frequencies, bigrams);
} catch (IOException e) {
Log.e(TAG, "IO exception while reading file", e);
} catch (UnsupportedFormatException e) {
@@ -140,10 +146,11 @@ public final class UserHistoryDictIOUtils {
* Adds all unigrams and bigrams in maps to OnAddWordListener.
*/
@UsedForTesting
- static void addWordsFromWordMap(final Map<Integer, String> unigrams,
- final Map<Integer, Integer> frequencies,
- final Map<Integer, ArrayList<PendingAttribute>> bigrams, final OnAddWordListener to) {
- for (Map.Entry<Integer, String> entry : unigrams.entrySet()) {
+ static void addWordsFromWordMap(final TreeMap<Integer, String> unigrams,
+ final TreeMap<Integer, Integer> frequencies,
+ final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams,
+ final OnAddWordListener to) {
+ for (Entry<Integer, String> entry : unigrams.entrySet()) {
final String word1 = entry.getValue();
final int unigramFrequency = frequencies.get(entry.getKey());
to.setUnigram(word1, null, unigramFrequency);
@@ -156,7 +163,7 @@ public final class UserHistoryDictIOUtils {
continue;
}
to.setBigram(word1, word2,
- BinaryDictInputOutput.reconstructBigramFrequency(unigramFrequency,
+ BinaryDictIOUtils.reconstructBigramFrequency(unigramFrequency,
attr.mFrequency));
}
}
diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
index 713a45bda..1992b2f5d 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
@@ -23,7 +23,9 @@ import java.util.concurrent.TimeUnit;
public final class UserHistoryForgettingCurveUtils {
private static final String TAG = UserHistoryForgettingCurveUtils.class.getSimpleName();
private static final boolean DEBUG = false;
- private static final int FC_FREQ_MAX = 127;
+ private static final int DEFAULT_FC_FREQ = 127;
+ private static final int BOOSTED_FC_FREQ = 200;
+ private static int FC_FREQ_MAX = DEFAULT_FC_FREQ;
/* package */ static final int COUNT_MAX = 3;
private static final int FC_LEVEL_MAX = 3;
/* package */ static final int ELAPSED_TIME_MAX = 15;
@@ -33,6 +35,14 @@ public final class UserHistoryForgettingCurveUtils {
private static final int HALF_LIFE_HOURS = 48;
private static final int MAX_PUSH_ELAPSED = (FC_LEVEL_MAX + 1) * (ELAPSED_TIME_MAX + 1);
+ public static void boostMaxFreqForDebug() {
+ FC_FREQ_MAX = BOOSTED_FC_FREQ;
+ }
+
+ public static void resetMaxFreqForDebug() {
+ FC_FREQ_MAX = DEFAULT_FC_FREQ;
+ }
+
private UserHistoryForgettingCurveUtils() {
// This utility class is not publicly instantiable.
}
diff --git a/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
index 161386e2e..a75d353c9 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.latin.utils;
import android.inputmethodservice.InputMethodService;
import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.settings.Settings;
public final class UserLogRingCharBuffer {
@@ -64,6 +65,9 @@ public final class UserLogRingCharBuffer {
if (!mEnabled) {
return;
}
+ if (LatinImeLogger.sUsabilityStudy) {
+ UsabilityStudyLogUtils.getInstance().writeChar(c, x, y);
+ }
mCharBuf[mEnd] = c;
mXBuf[mEnd] = x;
mYBuf[mEnd] = y;