aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java2
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java2
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryWriter.java5
-rw-r--r--java/src/com/android/inputmethod/latin/InputView.java32
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java133
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java6
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java10
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java104
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java109
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FormatSpec.java44
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java51
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java10
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java (renamed from java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateListener.java)11
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java84
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsFragment.java4
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java4
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java25
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java13
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java12
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ResourceUtils.java31
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java4
23 files changed, 485 insertions, 219 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index fa301b5a6..d0a4afd50 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -235,7 +235,7 @@ final public class BinaryDictionaryGetter {
new BinaryDictInputOutput.ByteBufferWrapper(inStream.getChannel().map(
FileChannel.MapMode.READ_ONLY, 0, f.length()));
final int magic = buffer.readInt();
- if (magic != FormatSpec.VERSION_2_MAGIC_NUMBER) {
+ if (magic != FormatSpec.MAGIC_NUMBER) {
return false;
}
final int formatVersion = buffer.readInt();
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index f91a21c7a..8aec03f71 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -187,6 +187,7 @@ public final class Constants {
public static final int CODE_ACTION_NEXT = -8;
public static final int CODE_ACTION_PREVIOUS = -9;
public static final int CODE_LANGUAGE_SWITCH = -10;
+ public static final int CODE_EMOJI = -11;
public static final int CODE_SHIFT_ENTER = -12;
// Code value representing the code is not specified.
public static final int CODE_UNSPECIFIED = -13;
@@ -207,6 +208,7 @@ public final class Constants {
case CODE_ACTION_NEXT: return "actionNext";
case CODE_ACTION_PREVIOUS: return "actionPrevious";
case CODE_LANGUAGE_SWITCH: return "languageSwitch";
+ case CODE_EMOJI: return "emoji";
case CODE_SHIFT_ENTER: return "shiftEnter";
case CODE_UNSPECIFIED: return "unspec";
case CODE_TAB: return "tab";
diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
index 8be04c1c0..47151bf61 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
@@ -37,10 +37,9 @@ import java.util.HashMap;
* An in memory dictionary for memorizing entries and writing a binary dictionary.
*/
public class DictionaryWriter extends AbstractDictionaryWriter {
- // TODO: Regenerate version 3 binary dictionary.
- private static final int BINARY_DICT_VERSION = 2;
+ private static final int BINARY_DICT_VERSION = 3;
private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
- new FormatSpec.FormatOptions(BINARY_DICT_VERSION);
+ new FormatSpec.FormatOptions(BINARY_DICT_VERSION, true /* supportsDynamicUpdate */);
private FusionDictionary mFusionDictionary;
diff --git a/java/src/com/android/inputmethod/latin/InputView.java b/java/src/com/android/inputmethod/latin/InputView.java
index 5359c8185..81ccf83d8 100644
--- a/java/src/com/android/inputmethod/latin/InputView.java
+++ b/java/src/com/android/inputmethod/latin/InputView.java
@@ -24,7 +24,7 @@ import android.view.View;
import android.widget.LinearLayout;
public final class InputView extends LinearLayout {
- private View mSuggestionStripContainer;
+ private View mSuggestionStripView;
private View mKeyboardView;
private int mKeyboardTopPadding;
@@ -33,33 +33,29 @@ public final class InputView extends LinearLayout {
private final Rect mEventForwardingRect = new Rect();
private final Rect mEventReceivingRect = new Rect();
- public InputView(Context context, AttributeSet attrs) {
+ public InputView(final Context context, final AttributeSet attrs) {
super(context, attrs, 0);
}
- public void setKeyboardGeometry(int keyboardTopPadding) {
+ public void setKeyboardGeometry(final int keyboardTopPadding) {
mKeyboardTopPadding = keyboardTopPadding;
}
@Override
protected void onFinishInflate() {
- mSuggestionStripContainer = findViewById(R.id.suggestions_container);
+ mSuggestionStripView = findViewById(R.id.suggestion_strip_view);
mKeyboardView = findViewById(R.id.keyboard_view);
}
@Override
- public boolean dispatchTouchEvent(MotionEvent me) {
- if (mSuggestionStripContainer.getVisibility() == VISIBLE
- && mKeyboardView.getVisibility() == VISIBLE
- && forwardTouchEvent(me)) {
- return true;
+ public boolean dispatchTouchEvent(final MotionEvent me) {
+ if (mSuggestionStripView.getVisibility() != VISIBLE
+ || mKeyboardView.getVisibility() != VISIBLE) {
+ return super.dispatchTouchEvent(me);
}
- return super.dispatchTouchEvent(me);
- }
- // The touch events that hit the top padding of keyboard should be forwarded to
- // {@link SuggestionStripView}.
- private boolean forwardTouchEvent(MotionEvent me) {
+ // The touch events that hit the top padding of keyboard should be forwarded to
+ // {@link SuggestionStripView}.
final Rect rect = mInputViewRect;
this.getGlobalVisibleRect(rect);
final int x = (int)me.getX() + rect.left;
@@ -68,7 +64,7 @@ public final class InputView extends LinearLayout {
final Rect forwardingRect = mEventForwardingRect;
mKeyboardView.getGlobalVisibleRect(forwardingRect);
if (!mIsForwardingEvent && !forwardingRect.contains(x, y)) {
- return false;
+ return super.dispatchTouchEvent(me);
}
final int forwardingLimitY = forwardingRect.top + mKeyboardTopPadding;
@@ -93,11 +89,11 @@ public final class InputView extends LinearLayout {
}
if (!sendToTarget) {
- return false;
+ return super.dispatchTouchEvent(me);
}
final Rect receivingRect = mEventReceivingRect;
- mSuggestionStripContainer.getGlobalVisibleRect(receivingRect);
+ mSuggestionStripView.getGlobalVisibleRect(receivingRect);
final int translatedX = x - receivingRect.left;
final int translatedY;
if (y < forwardingLimitY) {
@@ -107,7 +103,7 @@ public final class InputView extends LinearLayout {
translatedY = y - receivingRect.top;
}
me.setLocation(translatedX, translatedY);
- mSuggestionStripContainer.dispatchTouchEvent(me);
+ mSuggestionStripView.dispatchTouchEvent(me);
return true;
}
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 385e884ab..a7798e335 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -31,7 +31,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.net.ConnectivityManager;
@@ -51,7 +50,6 @@ import android.util.Printer;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
@@ -76,6 +74,7 @@ import com.android.inputmethod.keyboard.MainKeyboardView;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.personalization.PersonalizationDictionaryHelper;
+import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegister;
import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary;
import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary;
import com.android.inputmethod.latin.settings.Settings;
@@ -150,9 +149,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private final Settings mSettings;
- private View mExtractArea;
- private View mKeyPreviewBackingView;
- private View mSuggestionsContainer;
+ private View mInputView;
+ private int mInputViewMinHeight;
private SuggestionStripView mSuggestionStripView;
// Never null
private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
@@ -473,6 +471,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
KeyboardSwitcher.init(this);
AudioAndHapticFeedbackManager.init(this);
AccessibilityUtils.init(this);
+ PersonalizationDictionarySessionRegister.init(this);
super.onCreate();
@@ -653,6 +652,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mOptionsDialog.dismiss();
}
}
+ PersonalizationDictionarySessionRegister.onConfigurationChanged(this, conf);
super.onConfigurationChanged(conf);
}
@@ -661,18 +661,25 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled);
}
+ private void setInputViewMinHeight(final int minHeight) {
+ if (mInputView != null && mInputViewMinHeight != minHeight) {
+ mInputView.setMinimumHeight(minHeight);
+ mInputViewMinHeight = minHeight;
+ }
+ }
+
@Override
- public void setInputView(final View view) {
- super.setInputView(view);
- mExtractArea = getWindow().getWindow().getDecorView()
- .findViewById(android.R.id.extractArea);
- mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing);
- mSuggestionsContainer = view.findViewById(R.id.suggestions_container);
- mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view);
- if (mSuggestionStripView != null)
- mSuggestionStripView.setListener(this, view);
+ public void setInputView(final View inputView) {
+ super.setInputView(inputView);
+ mInputView = inputView;
+ setInputViewMinHeight(0);
+ mSuggestionStripView = (SuggestionStripView)inputView.findViewById(
+ R.id.suggestion_strip_view);
+ if (mSuggestionStripView != null) {
+ mSuggestionStripView.setListener(this, inputView);
+ }
if (LatinImeLogger.sVISUALDEBUG) {
- mKeyPreviewBackingView.setBackgroundColor(0x10FF0000);
+ inputView.setBackgroundColor(0x10FF0000);
}
}
@@ -848,8 +855,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mainKeyboardView.setSlidingKeyInputPreviewEnabled(
currentSettingsValues.mSlidingKeyInputPreviewEnabled);
mainKeyboardView.setGestureHandlingEnabledByUser(
- currentSettingsValues.mGestureInputEnabled);
- mainKeyboardView.setGesturePreviewMode(currentSettingsValues.mGesturePreviewTrailEnabled,
+ currentSettingsValues.mGestureInputEnabled,
+ currentSettingsValues.mGestureTrailEnabled,
currentSettingsValues.mGestureFloatingPreviewTextEnabled);
// If we have a user dictionary addition in progress, we should check now if we should
@@ -1111,19 +1118,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void setSuggestionStripShownInternal(final boolean shown,
final boolean needsInputViewShown) {
// TODO: Modify this if we support suggestions with hard keyboard
- if (onEvaluateInputViewShown() && mSuggestionsContainer != null) {
+ if (onEvaluateInputViewShown() && mSuggestionStripView != null) {
final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
final boolean inputViewShown = (mainKeyboardView != null)
? mainKeyboardView.isShown() : false;
final boolean shouldShowSuggestions = shown
&& (needsInputViewShown ? inputViewShown : true);
if (isFullscreenMode()) {
- mSuggestionsContainer.setVisibility(
+ mSuggestionStripView.setVisibility(
shouldShowSuggestions ? View.VISIBLE : View.GONE);
} else {
- mSuggestionsContainer.setVisibility(
+ mSuggestionStripView.setVisibility(
shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE);
}
+ if (shouldShowSuggestions && mainKeyboardView != null) {
+ final int remainingHeight = getWindow().getWindow().getDecorView().getHeight()
+ - mainKeyboardView.getHeight() - mSuggestionStripView.getHeight();
+ mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight);
+ }
}
}
@@ -1131,64 +1143,37 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
}
- private int getAdjustedBackingViewHeight() {
- final int currentHeight = mKeyPreviewBackingView.getHeight();
- if (currentHeight > 0) {
- return currentHeight;
- }
-
- final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
- if (mainKeyboardView == null) {
- return 0;
- }
- final int keyboardHeight = mainKeyboardView.getHeight();
- final int suggestionsHeight = mSuggestionsContainer.getHeight();
- final int displayHeight = getResources().getDisplayMetrics().heightPixels;
- final Rect rect = new Rect();
- mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect);
- final int notificationBarHeight = rect.top;
- final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight
- - keyboardHeight;
-
- final LayoutParams params = mKeyPreviewBackingView.getLayoutParams();
- params.height = mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight);
- mKeyPreviewBackingView.setLayoutParams(params);
- return params.height;
- }
-
@Override
public void onComputeInsets(final InputMethodService.Insets outInsets) {
super.onComputeInsets(outInsets);
final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
- if (mainKeyboardView == null || mSuggestionsContainer == null) {
+ if (mainKeyboardView == null || mSuggestionStripView == null) {
return;
}
- final int adjustedBackingHeight = getAdjustedBackingViewHeight();
- final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE);
- final int backingHeight = backingGone ? 0 : adjustedBackingHeight;
- // In fullscreen mode, the height of the extract area managed by InputMethodService should
- // be considered.
- // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}.
- final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0;
- final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0
- : mSuggestionsContainer.getHeight();
- final int extraHeight = extractHeight + backingHeight + suggestionsHeight;
- int visibleTopY = extraHeight;
+ // This method is never called when in fullscreen mode.
+ // The contentTop is the top coordinate of the keyboard. The application behind will be
+ // resized/panned above this coordibnate to be able to show an input field.
+ final int contentTop = mInputView.getHeight() - mainKeyboardView.getHeight();
+ final int suggestionsHeight = (mSuggestionStripView.getVisibility() == View.VISIBLE)
+ ? mSuggestionStripView.getHeight() : 0;
+ // The visibleTop is the top coordinates of the visible part of this IME. The application
+ // behind will never be resized, but may be panned or scrolled.
+ final int visibleTop = mainKeyboardView.isShowingMoreKeysPanel() ? 0
+ : contentTop - suggestionsHeight;
+ outInsets.contentTopInsets = contentTop;
+ outInsets.visibleTopInsets = visibleTop;
// Need to set touchable region only if input view is being shown
if (mainKeyboardView.isShown()) {
- if (mSuggestionsContainer.getVisibility() == View.VISIBLE) {
- visibleTopY -= suggestionsHeight;
- }
- final int touchY = mainKeyboardView.isShowingMoreKeysPanel() ? 0 : visibleTopY;
- final int touchWidth = mainKeyboardView.getWidth();
- final int touchHeight = mainKeyboardView.getHeight() + extraHeight
+ final int touchLeft = 0;
+ final int touchTop = visibleTop;
+ final int touchRight = touchLeft + mainKeyboardView.getWidth();
+ final int touchBottom = contentTop + mainKeyboardView.getHeight()
// Extend touchable region below the keyboard.
+ EXTENDED_TOUCHABLE_REGION_HEIGHT;
+ // The touch event on touchableRegion will be delivered to this IME.
+ outInsets.touchableRegion.set(touchLeft, touchTop, touchRight, touchBottom);
outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
- outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight);
}
- outInsets.contentTopInsets = visibleTopY;
- outInsets.visibleTopInsets = visibleTopY;
}
@Override
@@ -1211,11 +1196,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void updateFullscreenMode() {
super.updateFullscreenMode();
-
- if (mKeyPreviewBackingView == null) return;
- // In fullscreen mode, no need to have extra space to show the key preview.
- // If not, we should have extra space above the keyboard to show the key preview.
- mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE);
+ if (!isFullscreenMode()) {
+ // Expand the input view to cover entire display to be able to show key previews and
+ // more suggestions view that may be displayed above the keyboard.
+ setInputViewMinHeight(getResources().getDisplayMetrics().heightPixels);
+ }
}
// This will reset the whole input state to the starting state. It will clear
@@ -1512,6 +1497,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
case Constants.CODE_LANGUAGE_SWITCH:
handleLanguageSwitchKey();
break;
+ case Constants.CODE_EMOJI:
+ // TODO: Implement emoji keyboard switch.
+ break;
case Constants.CODE_ENTER:
final EditorInfo editorInfo = getCurrentInputEditorInfo();
final int imeOptionsActionId =
@@ -2529,7 +2517,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int maxFreq = AutoCorrectionUtils.getMaxFrequency(
suggest.getUnigramDictionaries(), suggestion);
if (maxFreq == 0) return null;
- userHistoryPredictionDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0);
+ userHistoryPredictionDictionary
+ .addToPersonalizationPredictionDictionary(prevWord, secondWord, maxFreq > 0);
return prevWord;
}
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index b69e3f8d2..35920f8cb 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -654,9 +654,11 @@ public final class RichInputConnection {
+ "\"" + periodSpace + "\" just before the cursor.");
return false;
}
+ // Double-space results in ". ". A backspace to cancel this should result in a single
+ // space in the text field, so we replace ". " with a single space.
deleteSurroundingText(2, 0);
- final String doubleSpace = " ";
- commitText(doubleSpace, 1);
+ final String singleSpace = " ";
+ commitText(singleSpace, 1);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.richInputConnection_revertDoubleSpacePeriod();
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
index 167c6915c..c7b063daf 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
@@ -145,21 +145,21 @@ public final class BinaryDictIOUtils {
* Reads unigrams and bigrams from the binary file.
* Doesn't make the memory representation of the dictionary.
*
- * @param buffer the buffer to read.
+ * @param reader the reader.
* @param words the map to store the address as a key and the word as a value.
* @param frequencies the map to store the address as a key and the frequency as a value.
* @param bigrams the map to store the address as a key and the list of address as a value.
* @throws IOException
* @throws UnsupportedFormatException
*/
- public static void readUnigramsAndBigramsBinary(final FusionDictionaryBufferInterface buffer,
+ public static void readUnigramsAndBigramsBinary(final BinaryDictReader reader,
final Map<Integer, String> words, final Map<Integer, Integer> frequencies,
final Map<Integer, ArrayList<PendingAttribute>> bigrams) throws IOException,
UnsupportedFormatException {
// Read header
- final FileHeader header = BinaryDictInputOutput.readHeader(buffer);
- readUnigramsAndBigramsBinaryInner(buffer, header.mHeaderSize, words, frequencies, bigrams,
- header.mFormatOptions);
+ final FileHeader header = BinaryDictInputOutput.readHeader(reader.getBuffer());
+ readUnigramsAndBigramsBinaryInner(reader.getBuffer(), header.mHeaderSize, words,
+ frequencies, bigrams, header.mFormatOptions);
}
/**
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index 1b187d85d..504349a0b 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -66,6 +66,7 @@ public final class BinaryDictInputOutput {
public void position(int newPosition);
public void put(final byte b);
public int limit();
+ @UsedForTesting
public int capacity();
}
@@ -1210,49 +1211,38 @@ public final class BinaryDictInputOutput {
ByteArrayOutputStream headerBuffer = new ByteArrayOutputStream(256);
// The magic number in big-endian order.
- if (version >= FormatSpec.FIRST_VERSION_WITH_HEADER_SIZE) {
- // Magic number for version 2+.
- headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_2_MAGIC_NUMBER >> 24)));
- headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_2_MAGIC_NUMBER >> 16)));
- headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_2_MAGIC_NUMBER >> 8)));
- headerBuffer.write((byte) (0xFF & FormatSpec.VERSION_2_MAGIC_NUMBER));
- // Dictionary version.
- headerBuffer.write((byte) (0xFF & (version >> 8)));
- headerBuffer.write((byte) (0xFF & version));
- } else {
- // Magic number for version 1.
- headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_1_MAGIC_NUMBER >> 8)));
- headerBuffer.write((byte) (0xFF & FormatSpec.VERSION_1_MAGIC_NUMBER));
- // Dictionary version.
- headerBuffer.write((byte) (0xFF & version));
- }
+ // Magic number for all versions.
+ headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 24)));
+ headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 16)));
+ headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 8)));
+ headerBuffer.write((byte) (0xFF & FormatSpec.MAGIC_NUMBER));
+ // Dictionary version.
+ headerBuffer.write((byte) (0xFF & (version >> 8)));
+ headerBuffer.write((byte) (0xFF & version));
+
// Options flags
final int options = makeOptionsValue(dict, formatOptions);
headerBuffer.write((byte) (0xFF & (options >> 8)));
headerBuffer.write((byte) (0xFF & options));
- if (version >= FormatSpec.FIRST_VERSION_WITH_HEADER_SIZE) {
- final int headerSizeOffset = headerBuffer.size();
- // Placeholder to be written later with header size.
- for (int i = 0; i < 4; ++i) {
- headerBuffer.write(0);
- }
- // Write out the options.
- for (final String key : dict.mOptions.mAttributes.keySet()) {
- final String value = dict.mOptions.mAttributes.get(key);
- CharEncoding.writeString(headerBuffer, key);
- CharEncoding.writeString(headerBuffer, value);
- }
- final int size = headerBuffer.size();
- final byte[] bytes = headerBuffer.toByteArray();
- // Write out the header size.
- bytes[headerSizeOffset] = (byte) (0xFF & (size >> 24));
- bytes[headerSizeOffset + 1] = (byte) (0xFF & (size >> 16));
- bytes[headerSizeOffset + 2] = (byte) (0xFF & (size >> 8));
- bytes[headerSizeOffset + 3] = (byte) (0xFF & (size >> 0));
- destination.write(bytes);
- } else {
- headerBuffer.writeTo(destination);
- }
+ final int headerSizeOffset = headerBuffer.size();
+ // Placeholder to be written later with header size.
+ for (int i = 0; i < 4; ++i) {
+ headerBuffer.write(0);
+ }
+ // Write out the options.
+ for (final String key : dict.mOptions.mAttributes.keySet()) {
+ final String value = dict.mOptions.mAttributes.get(key);
+ CharEncoding.writeString(headerBuffer, key);
+ CharEncoding.writeString(headerBuffer, value);
+ }
+ final int size = headerBuffer.size();
+ final byte[] bytes = headerBuffer.toByteArray();
+ // Write out the header size.
+ bytes[headerSizeOffset] = (byte) (0xFF & (size >> 24));
+ bytes[headerSizeOffset + 1] = (byte) (0xFF & (size >> 16));
+ bytes[headerSizeOffset + 2] = (byte) (0xFF & (size >> 8));
+ bytes[headerSizeOffset + 3] = (byte) (0xFF & (size >> 0));
+ destination.write(bytes);
headerBuffer.close();
@@ -1658,10 +1648,8 @@ public final class BinaryDictInputOutput {
*/
private static int getFormatVersion(final FusionDictionaryBufferInterface buffer)
throws IOException {
- final int magic_v1 = buffer.readUnsignedShort();
- if (FormatSpec.VERSION_1_MAGIC_NUMBER == magic_v1) return buffer.readUnsignedByte();
- final int magic_v2 = (magic_v1 << 16) + buffer.readUnsignedShort();
- if (FormatSpec.VERSION_2_MAGIC_NUMBER == magic_v2) return buffer.readUnsignedShort();
+ final int magic = buffer.readInt();
+ if (FormatSpec.MAGIC_NUMBER == magic) return buffer.readUnsignedShort();
return FormatSpec.NOT_A_VERSION_NUMBER;
}
@@ -1695,18 +1683,15 @@ public final class BinaryDictInputOutput {
final HashMap<String, String> attributes = new HashMap<String, String>();
final int headerSize;
- if (version < FormatSpec.FIRST_VERSION_WITH_HEADER_SIZE) {
- headerSize = buffer.position();
- } else {
- headerSize = buffer.readInt();
- populateOptions(buffer, headerSize, attributes);
- buffer.position(headerSize);
- }
+ headerSize = buffer.readInt();
if (headerSize < 0) {
throw new UnsupportedFormatException("header size can't be negative.");
}
+ populateOptions(buffer, headerSize, attributes);
+ buffer.position(headerSize);
+
final FileHeader header = new FileHeader(headerSize,
new FusionDictionary.DictionaryOptions(attributes,
0 != (optionsFlags & FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG),
@@ -1738,23 +1723,30 @@ public final class BinaryDictInputOutput {
* FusionDictionary structure. The optional dict argument is an existing dictionary to
* which words from the buffer should be added. If it is null, a new dictionary is created.
*
- * @param buffer the buffer to read.
+ * @param reader the reader.
* @param dict an optional dictionary to add words to, or null.
* @return the created (or merged) dictionary.
*/
@UsedForTesting
- public static FusionDictionary readDictionaryBinary(
- final FusionDictionaryBufferInterface buffer, final FusionDictionary dict)
- throws IOException, UnsupportedFormatException {
+ public static FusionDictionary readDictionaryBinary(final BinaryDictReader reader,
+ final FusionDictionary dict) throws FileNotFoundException, IOException,
+ UnsupportedFormatException {
// clear cache
wordCache.clear();
+ // if the buffer has not been opened, open the buffer with bytebuffer.
+ if (reader.getBuffer() == null) reader.openBuffer(
+ new BinaryDictReader.FusionDictionaryBufferFromByteBufferFactory());
+ if (reader.getBuffer() == null) {
+ MakedictLog.e("Cannot open the buffer");
+ }
+
// Read header
- final FileHeader header = readHeader(buffer);
+ final FileHeader header = readHeader(reader.getBuffer());
Map<Integer, Node> reverseNodeMapping = new TreeMap<Integer, Node>();
Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
- final Node root = readNode(buffer, header.mHeaderSize, reverseNodeMapping,
+ final Node root = readNode(reader.getBuffer(), header.mHeaderSize, reverseNodeMapping,
reverseGroupMapping, header.mFormatOptions);
FusionDictionary newDict = new FusionDictionary(root, header.mDictionaryOptions);
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java
new file mode 100644
index 000000000..57a583228
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java
@@ -0,0 +1,109 @@
+/*
+ * 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.makedict;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
+import com.android.inputmethod.latin.utils.ByteArrayWrapper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+public class BinaryDictReader {
+
+ public interface FusionDictionaryBufferFactory {
+ public FusionDictionaryBufferInterface getFusionDictionaryBuffer(final File file)
+ throws FileNotFoundException, IOException;
+ }
+
+ /**
+ * Creates FusionDictionaryBuffer from a ByteBuffer
+ */
+ public static final class FusionDictionaryBufferFromByteBufferFactory
+ implements FusionDictionaryBufferFactory {
+ @Override
+ public FusionDictionaryBufferInterface getFusionDictionaryBuffer(final File file)
+ throws FileNotFoundException, IOException {
+ FileInputStream inStream = null;
+ ByteBuffer buffer = null;
+ try {
+ inStream = new FileInputStream(file);
+ buffer = inStream.getChannel().map(FileChannel.MapMode.READ_ONLY,
+ 0, file.length());
+ } finally {
+ if (inStream != null) {
+ inStream.close();
+ }
+ }
+ if (buffer != null) {
+ return new BinaryDictInputOutput.ByteBufferWrapper(buffer);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Creates FusionDictionaryBuffer from a byte array
+ */
+ public static final class FusionDictionaryBufferFromByteArrayFactory
+ implements FusionDictionaryBufferFactory {
+ @Override
+ public FusionDictionaryBufferInterface getFusionDictionaryBuffer(final File file)
+ throws FileNotFoundException, IOException {
+ FileInputStream inStream = null;
+ try {
+ inStream = new FileInputStream(file);
+ final byte[] array = new byte[(int) file.length()];
+ inStream.read(array);
+ return new ByteArrayWrapper(array);
+ } finally {
+ if (inStream != null) {
+ inStream.close();
+ }
+ }
+ }
+ }
+
+ private final File mDictionaryBinaryFile;
+ private FusionDictionaryBufferInterface mFusionDictionaryBuffer;
+
+ public BinaryDictReader(final File file) {
+ mDictionaryBinaryFile = file;
+ mFusionDictionaryBuffer = null;
+ }
+
+ public void openBuffer(final FusionDictionaryBufferFactory factory)
+ throws FileNotFoundException, IOException {
+ mFusionDictionaryBuffer = factory.getFusionDictionaryBuffer(mDictionaryBinaryFile);
+ }
+
+ public FusionDictionaryBufferInterface getBuffer() {
+ return mFusionDictionaryBuffer;
+ }
+
+ @UsedForTesting
+ public FusionDictionaryBufferInterface openAndGetBuffer(
+ final FusionDictionaryBufferFactory factory)
+ throws FileNotFoundException, IOException {
+ openBuffer(factory);
+ return getBuffer();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index feadcda76..2bb5d8b6e 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin.makedict;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
@@ -25,6 +26,40 @@ import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions
public final class FormatSpec {
/*
+ * File header layout is as follows:
+ *
+ * v |
+ * e | MAGIC_NUMBER + version of the file format, 2 bytes.
+ * r |
+ * sion
+ *
+ * o |
+ * p | not used 4 bits
+ * t | has bigrams ? 1 bit, 1 = yes, 0 = no : CONTAINS_BIGRAMS_FLAG
+ * i | FRENCH_LIGATURE_PROCESSING_FLAG
+ * o | supports dynamic updates ? 1 bit, 1 = yes, 0 = no : SUPPORTS_DYNAMIC_UPDATE
+ * n | GERMAN_UMLAUT_PROCESSING_FLAG
+ * f |
+ * lags
+ *
+ * h |
+ * e | size of the file header, 4bytes
+ * a | including the size of the magic number, the option flags and the header size
+ * d |
+ * ersize
+ *
+ * | attributes list
+ *
+ * attributes list is:
+ * <key> = | string of characters at the char format described below, with the terminator used
+ * | to signal the end of the string.
+ * <value> = | string of characters at the char format described below, with the terminator used
+ * | to signal the end of the string.
+ * if the size of already read < headersize, goto key.
+ *
+ */
+
+ /*
* Array of Node(FusionDictionary.Node) layout is as follows:
*
* g |
@@ -150,12 +185,10 @@ public final class FormatSpec {
* if (FLAG_ATTRIBUTE_HAS_NEXT goto flags
*/
- static final int VERSION_1_MAGIC_NUMBER = 0x78B1;
- public static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
- static final int MINIMUM_SUPPORTED_VERSION = 1;
+ public static final int MAGIC_NUMBER = 0x9BC13AFE;
+ static final int MINIMUM_SUPPORTED_VERSION = 2;
static final int MAXIMUM_SUPPORTED_VERSION = 3;
static final int NOT_A_VERSION_NUMBER = -1;
- static final int FIRST_VERSION_WITH_HEADER_SIZE = 2;
static final int FIRST_VERSION_WITH_DYNAMIC_UPDATE = 3;
// These options need to be the same numeric values as the one in the native reading code.
@@ -236,9 +269,12 @@ public final class FormatSpec {
public static final class FormatOptions {
public final int mVersion;
public final boolean mSupportsDynamicUpdate;
+ @UsedForTesting
public FormatOptions(final int version) {
this(version, false);
}
+
+ @UsedForTesting
public FormatOptions(final int version, final boolean supportsDynamicUpdate) {
mVersion = version;
if (version < FIRST_VERSION_WITH_DYNAMIC_UPDATE && supportsDynamicUpdate) {
diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
index 9d041f4eb..065e00e4a 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
@@ -28,9 +28,10 @@ import com.android.inputmethod.latin.ExpandableDictionary;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.makedict.BinaryDictReader;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.settings.Settings;
-import com.android.inputmethod.latin.utils.ByteArrayWrapper;
+import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils;
import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface;
import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener;
@@ -38,7 +39,6 @@ import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils;
import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -49,9 +49,6 @@ import java.util.concurrent.locks.ReentrantLock;
* This class is a base class of a dictionary for the personalized prediction language model.
*/
public abstract class DynamicPredictionDictionaryBase extends ExpandableDictionary {
- public static void registerUpdateListener(PersonalizationDictionaryUpdateListener listener) {
- // TODO: Implement
- }
private static final String TAG = DynamicPredictionDictionaryBase.class.getSimpleName();
public static final boolean DBG_SAVE_RESTORE = false;
@@ -75,8 +72,11 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableDictiona
private final ReentrantLock mBigramListLock = new ReentrantLock();
private final SharedPreferences mPrefs;
+ private final ArrayList<PersonalizationDictionaryUpdateSession> mSessions =
+ CollectionUtils.newArrayList();
+
// Should always be false except when we use this class for test
- @UsedForTesting boolean isTest = false;
+ @UsedForTesting boolean mIsTest = false;
/* package */ DynamicPredictionDictionaryBase(final Context context, final String locale,
final SharedPreferences sp, final String dictionaryType) {
@@ -118,14 +118,15 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableDictiona
}
/**
- * Pair will be added to the user history dictionary.
+ * Pair will be added to the personalization prediction dictionary.
*
* The first word may be null. That means we don't know the context, in other words,
* it's only a unigram. The first word may also be an empty string : this means start
* context, as in beginning of a sentence for example.
* The second word may not be null (a NullPointerException would be thrown).
*/
- public int addToUserHistory(final String word1, final String word2, final boolean isValid) {
+ public int addToPersonalizationPredictionDictionary(
+ final String word1, final String word2, final boolean isValid) {
if (word2.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH ||
(word1 != null && word1.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) {
return -1;
@@ -232,27 +233,17 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableDictiona
};
// Load the dictionary from binary file
- FileInputStream inStream = null;
+ final BinaryDictReader reader = new BinaryDictReader(
+ new File(getContext().getFilesDir(), fileName));
try {
- final File file = new File(getContext().getFilesDir(), fileName);
- final byte[] buffer = new byte[(int)file.length()];
- inStream = new FileInputStream(file);
- inStream.read(buffer);
- UserHistoryDictIOUtils.readDictionaryBinary(
- new ByteArrayWrapper(buffer), listener);
+ reader.openBuffer(new BinaryDictReader.FusionDictionaryBufferFromByteArrayFactory());
+ UserHistoryDictIOUtils.readDictionaryBinary(reader, listener);
} catch (FileNotFoundException e) {
// This is an expected condition: we don't have a user history dictionary for this
// language yet. It will be created sometime later.
} catch (IOException e) {
Log.e(TAG, "IOException on opening a bytebuffer", e);
} finally {
- if (inStream != null) {
- try {
- inStream.close();
- } catch (IOException e) {
- // do nothing
- }
- }
if (PROFILE_SAVE_RESTORE) {
final long diff = System.currentTimeMillis() - now;
Log.d(TAG, "PROF: Load UserHistoryDictionary: "
@@ -296,8 +287,8 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableDictiona
@Override
protected Void doInBackground(final Void... v) {
- if (mDynamicPredictionDictionary.isTest) {
- // If isTest == true, wait until the lock is released.
+ if (mDynamicPredictionDictionary.mIsTest) {
+ // If mIsTest == true, wait until the lock is released.
mDynamicPredictionDictionary.mBigramListLock.lock();
try {
doWriteTaskLocked();
@@ -393,9 +384,19 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableDictiona
final String word1, final String word2, final boolean isValid) {
mBigramListLock.lock();
try {
- addToUserHistory(word1, word2, isValid);
+ addToPersonalizationPredictionDictionary(word1, word2, isValid);
} finally {
mBigramListLock.unlock();
}
}
+
+ public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) {
+ session.setPredictionDictionary(mLocale, this);
+ mSessions.add(session);
+ session.onDictionaryReady();
+ }
+
+ public void unRegisterUpdateSession(PersonalizationDictionaryUpdateSession session) {
+ mSessions.remove(session);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
index 19554d639..e38a235e9 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
@@ -27,7 +27,7 @@ import android.content.Context;
public class PersonalizationDictionary extends ExpandableBinaryDictionary {
private static final String NAME = "personalization";
- public static void registerUpdateListener(PersonalizationDictionaryUpdateListener listener) {
+ public static void registerUpdateListener(PersonalizationDictionaryUpdateSession listener) {
// TODO: Implement
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
index 9f013df1c..b4fd25024 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
@@ -20,6 +20,7 @@ import com.android.inputmethod.latin.utils.CollectionUtils;
import android.content.Context;
import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
import android.util.Log;
import java.lang.ref.SoftReference;
@@ -58,6 +59,15 @@ public class PersonalizationDictionaryHelper {
}
}
+ public static void registerPersonalizationDictionaryUpdateSession(final Context context,
+ final PersonalizationDictionaryUpdateSession session) {
+ final PersonalizationPredictionDictionary dictionary =
+ getPersonalizationPredictionDictionary(context,
+ context.getResources().getConfiguration().locale.toString(),
+ PreferenceManager.getDefaultSharedPreferences(context));
+ dictionary.registerUpdateSession(session);
+ }
+
public static PersonalizationPredictionDictionary getPersonalizationPredictionDictionary(
final Context context, final String locale, final SharedPreferences sp) {
synchronized (sLangPersonalizationDictCache) {
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateListener.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java
index c78e5a95b..534d3c518 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateListener.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java
@@ -16,6 +16,13 @@
package com.android.inputmethod.latin.personalization;
-public interface PersonalizationDictionaryUpdateListener {
- // TODO: Implement
+import android.content.Context;
+import android.content.res.Configuration;
+
+public class PersonalizationDictionarySessionRegister {
+ public static void init(Context context) {
+ }
+
+ public static void onConfigurationChanged(final Context context, final Configuration conf) {
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
new file mode 100644
index 000000000..e9dbbc273
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
@@ -0,0 +1,84 @@
+/*
+ * 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.personalization;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * This class is a session where a data provider can communicate with a personalization
+ * dictionary.
+ */
+public abstract class PersonalizationDictionaryUpdateSession {
+ /**
+ * This class is a parameter for a new unigram or bigram word which will be added
+ * to the personalization dictionary.
+ */
+ public static class PersonalizationLanguageModelParam {
+ public final String mWord0;
+ public final String mWord1;
+ public final boolean mIsValid;
+ public final int mFrequency;
+ public PersonalizationLanguageModelParam(String word0, String word1, boolean isValid,
+ int frequency) {
+ mWord0 = word0;
+ mWord1 = word1;
+ mIsValid = isValid;
+ mFrequency = frequency;
+ }
+ }
+
+ // TODO: Use a dynamic binary dictionary instead
+ public WeakReference<DynamicPredictionDictionaryBase> mPredictionDictionary;
+ public String mLocale;
+
+ public abstract void onDictionaryReady();
+
+ public void setPredictionDictionary(String locale, DynamicPredictionDictionaryBase dictionary) {
+ mPredictionDictionary = new WeakReference<DynamicPredictionDictionaryBase>(dictionary);
+ mLocale = locale;
+ }
+
+ protected DynamicPredictionDictionaryBase getPredictionDictionary() {
+ return mPredictionDictionary == null ? null : mPredictionDictionary.get();
+ }
+
+ private void unsetPredictionDictionary() {
+ final DynamicPredictionDictionaryBase dictionary = getPredictionDictionary();
+ if (dictionary == null) {
+ return;
+ }
+ dictionary.unRegisterUpdateSession(this);
+ }
+
+
+ public void closeSession() {
+ unsetPredictionDictionary();
+ }
+
+ public void addToPersonalizationDictionary(
+ final ArrayList<PersonalizationLanguageModelParam> lmParams) {
+ final DynamicPredictionDictionaryBase dictionary = getPredictionDictionary();
+ if (dictionary == null) {
+ return;
+ }
+ for (final PersonalizationLanguageModelParam lmParam : lmParams) {
+ dictionary.addToPersonalizationPredictionDictionary(
+ lmParam.mWord0, lmParam.mWord1, lmParam.mIsValid);
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index 446777704..1677e1828 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -229,10 +229,10 @@ public final class SettingsFragment extends InputMethodSettingsFragment
if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) {
removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen());
- } else {
- AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this);
}
+ AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this);
+
setupKeyLongpressTimeoutSettings(prefs, res);
setupKeypressVibrationDurationSettings(prefs, res);
setupKeypressSoundVolumeSettings(prefs, res);
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 8aafb0738..a25cf620c 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -71,7 +71,7 @@ public final class SettingsValues {
// Use bigrams to predict the next word when there is no input for it yet
public final boolean mBigramPredictionEnabled;
public final boolean mGestureInputEnabled;
- public final boolean mGesturePreviewTrailEnabled;
+ public final boolean mGestureTrailEnabled;
public final boolean mGestureFloatingPreviewTextEnabled;
public final boolean mSlidingKeyInputPreviewEnabled;
public final int mKeyLongpressTimeout;
@@ -157,7 +157,7 @@ public final class SettingsValues {
mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res);
- mGesturePreviewTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true);
+ mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true);
mGestureFloatingPreviewTextEnabled = prefs.getBoolean(
Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true);
mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 692e7392c..eb6d7c106 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -20,7 +20,10 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.service.textservice.SpellCheckerService;
+import android.text.InputType;
import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
import android.view.textservice.SuggestionsInfo;
import com.android.inputmethod.keyboard.KeyboardLayoutSet;
@@ -33,6 +36,7 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary;
import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary;
import com.android.inputmethod.latin.UserBinaryDictionary;
+import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.LocaleUtils;
import com.android.inputmethod.latin.utils.StringUtils;
@@ -58,6 +62,9 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
public static final String PREF_USE_CONTACTS_KEY = "pref_spellcheck_use_contacts";
+ private static final int SPELLCHECKER_DUMMY_KEYBOARD_WIDTH = 480;
+ private static final int SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT = 368;
+
private final static String[] EMPTY_STRING_ARRAY = new String[0];
private Map<String, DictionaryPool> mDictionaryPools = CollectionUtils.newSynchronizedTreeMap();
private Map<String, UserBinaryDictionary> mUserDictionaries =
@@ -401,9 +408,9 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
public DictAndKeyboard createDictAndKeyboard(final Locale locale) {
final int script = getScriptFromLocale(locale);
final String keyboardLayoutName = getKeyboardLayoutNameForScript(script);
- final KeyboardLayoutSet keyboardLayoutSet =
- KeyboardLayoutSet.createKeyboardSetForSpellChecker(this, locale.toString(),
- keyboardLayoutName);
+ final InputMethodSubtype subtype = AdditionalSubtypeUtils.createAdditionalSubtype(
+ locale.toString(), keyboardLayoutName, null);
+ final KeyboardLayoutSet keyboardLayoutSet = createKeyboardSetForSpellChecker(subtype);
final DictionaryCollection dictionaryCollection =
DictionaryFactory.createMainDictionaryFromManager(this, locale,
@@ -431,4 +438,16 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
}
return new DictAndKeyboard(dictionaryCollection, keyboardLayoutSet);
}
+
+ private KeyboardLayoutSet createKeyboardSetForSpellChecker(final InputMethodSubtype subtype) {
+ final EditorInfo editorInfo = new EditorInfo();
+ editorInfo.inputType = InputType.TYPE_CLASS_TEXT;
+ final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(this, editorInfo);
+ builder.setKeyboardGeometry(
+ SPELLCHECKER_DUMMY_KEYBOARD_WIDTH, SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT);
+ builder.setSubtype(subtype);
+ builder.setIsSpellChecker(true /* isSpellChecker */);
+ builder.disableTouchPositionCorrectionData();
+ return builder.build();
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 1dd04fc4d..bcf64a8e8 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -177,20 +177,9 @@ final class SuggestionStripLayoutHelper {
return mMaxMoreSuggestionsRow;
}
- private int getMoreSuggestionsHeight() {
- return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
- }
-
- public int setMoreSuggestionsHeight(final int remainingHeight) {
- final int currentHeight = getMoreSuggestionsHeight();
- if (currentHeight <= remainingHeight) {
- return currentHeight;
- }
-
+ public void setMoreSuggestionsHeight(final int remainingHeight) {
mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
/ mMoreSuggestionsRowHeight;
- final int newHeight = getMoreSuggestionsHeight();
- return newHeight;
}
private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 497a791d9..2644f3c9c 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -135,8 +135,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- public int setMoreSuggestionsHeight(final int remainingHeight) {
- return mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
+ public void setMoreSuggestionsHeight(final int remainingHeight) {
+ mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
}
public boolean isShowingAddToDictionaryHint() {
@@ -270,15 +270,10 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return super.dispatchTouchEvent(me);
}
- final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
final int action = me.getAction();
- final long eventTime = me.getEventTime();
final int index = me.getActionIndex();
- final int id = me.getPointerId(index);
final int x = (int)me.getX(index);
final int y = (int)me.getY(index);
- final int translatedX = moreKeysPanel.translateX(x);
- final int translatedY = moreKeysPanel.translateY(y);
if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) {
if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance
@@ -295,7 +290,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
// MORE_SUGGESTIONS_IN_SLIDING_MODE
- mMoreSuggestionsView.processMotionEvent(action, translatedX, translatedY, id, eventTime);
+ me.setLocation(mMoreSuggestionsView.translateX(x), mMoreSuggestionsView.translateY(y));
+ mMoreSuggestionsView.onTouchEvent(me);
return true;
}
diff --git a/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
index ffec57548..22c92446a 100644
--- a/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
@@ -20,10 +20,12 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.R;
import java.util.ArrayList;
import java.util.HashMap;
@@ -215,6 +217,35 @@ public final class ResourceUtils {
return null;
}
+ public static int getDefaultKeyboardWidth(final Resources res) {
+ final DisplayMetrics dm = res.getDisplayMetrics();
+ return dm.widthPixels;
+ }
+
+ public static int getDefaultKeyboardHeight(final Resources res) {
+ final DisplayMetrics dm = res.getDisplayMetrics();
+ final String keyboardHeightString = getDeviceOverrideValue(res, R.array.keyboard_heights);
+ final float keyboardHeight;
+ if (TextUtils.isEmpty(keyboardHeightString)) {
+ keyboardHeight = res.getDimension(R.dimen.keyboardHeight);
+ } else {
+ keyboardHeight = Float.parseFloat(keyboardHeightString) * dm.density;
+ }
+ final float maxKeyboardHeight = res.getFraction(
+ R.fraction.maxKeyboardHeight, dm.heightPixels, dm.heightPixels);
+ float minKeyboardHeight = res.getFraction(
+ R.fraction.minKeyboardHeight, dm.heightPixels, dm.heightPixels);
+ if (minKeyboardHeight < 0.0f) {
+ // Specified fraction was negative, so it should be calculated against display
+ // width.
+ minKeyboardHeight = -res.getFraction(
+ R.fraction.minKeyboardHeight, dm.widthPixels, dm.widthPixels);
+ }
+ // Keyboard height will not exceed maxKeyboardHeight and will not be less than
+ // minKeyboardHeight.
+ return (int)Math.max(Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
+ }
+
public static boolean isValidFraction(final float fraction) {
return fraction >= 0.0f;
}
diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
index d02f7187e..a0ad27cfb 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
@@ -21,7 +21,7 @@ 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.BinaryDictReader;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
@@ -118,13 +118,13 @@ public final class UserHistoryDictIOUtils {
/**
* Reads dictionary from file.
*/
- public static void readDictionaryBinary(final FusionDictionaryBufferInterface buffer,
+ public static void readDictionaryBinary(final BinaryDictReader reader,
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();
try {
- BinaryDictIOUtils.readUnigramsAndBigramsBinary(buffer, unigrams, frequencies,
+ BinaryDictIOUtils.readUnigramsAndBigramsBinary(reader, unigrams, frequencies,
bigrams);
} catch (IOException e) {
Log.e(TAG, "IO exception while reading file", e);
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;