diff options
Diffstat (limited to 'java')
34 files changed, 635 insertions, 389 deletions
diff --git a/java/res/raw/main_pt_br.dict b/java/res/raw/main_pt_br.dict Binary files differindex 28db0ed74..8c1449919 100644 --- a/java/res/raw/main_pt_br.dict +++ b/java/res/raw/main_pt_br.dict diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index afd6a0db6..1ebe4d33a 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Sleutelopspringer-wagperiode"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen wagperiode nie"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Verstek"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string> + <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Stel kontakname voor"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gebruik name van kontakte vir voorstelle en korreksies"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelspasie-punt"</string> diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index 738368205..1333f0f04 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -42,8 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"कुंजी पॉपअप खारिज़ विलंब"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"कोई विलंब नहीं"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"डिफ़ॉल्ट"</string> - <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> - <skip /> + <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> मिलीसेकंड"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"संपर्क नाम सुझाएं"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"सुझाव और सुधार के लिए संपर्क से नामों का उपयोग करें"</string> <string name="use_double_space_period" msgid="8781529969425082860">"दोहरे स्पेस वाला पीरियड"</string> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index c0085bb7a..ad0029efb 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Одложи одбац. иск. прозора тастера"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без одлагања"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Подразумевано"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> + <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Предложи имена контаката"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Користи имена из Контаката за предлоге и исправке"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Тачка и размак"</string> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index 462f7c938..e98a31e73 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -42,8 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tuş popup\'ının kapatılmasını geciktirme"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Gecikme yok"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Varsayılan"</string> - <!-- no translation found for settings_keypress_vibration_duration (489402970497503329) --> - <skip /> + <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Kişi Adları öner"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Öneri ve düzeltmeler için Kişiler\'deki adları kullan"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Çift boşlukla nokta ekleme"</string> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index 32544fa75..f6688c2e2 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -42,7 +42,7 @@ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Затримка клавіши закриття"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без затримки"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"За умовчанням"</string> - <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> мсек"</string> + <string name="settings_keypress_vibration_duration" msgid="489402970497503329">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Пропон. імена контактів"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Використ. імена зі списку контактів для пропозицій і виправлень"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Крапка подвійним пробілом"</string> diff --git a/java/src/com/android/inputmethod/event/Combiner.java b/java/src/com/android/inputmethod/event/Combiner.java new file mode 100644 index 000000000..ab6b70c04 --- /dev/null +++ b/java/src/com/android/inputmethod/event/Combiner.java @@ -0,0 +1,29 @@ +/* + * 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.event; + +/** + * A generic interface for combiners. + */ +public interface Combiner { + /** + * Combine an event with the existing state and return the new event. + * @param event the event to combine with the existing state. + * @return the resulting event. + */ + Event combine(Event event); +} diff --git a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java new file mode 100644 index 000000000..52987d571 --- /dev/null +++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java @@ -0,0 +1,61 @@ +/* + * 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.event; + +import android.text.TextUtils; +import android.view.KeyCharacterMap; + +import com.android.inputmethod.latin.Constants; + +/** + * A combiner that handles dead keys. + */ +public class DeadKeyCombiner implements Combiner { + final StringBuilder mDeadSequence = new StringBuilder(); + + @Override + public Event combine(final Event event) { + if (null == event) return null; // Just in case some combiner is broken + if (TextUtils.isEmpty(mDeadSequence)) { + if (event.isDead()) { + mDeadSequence.appendCodePoint(event.mCodePoint); + } + return event; + } else { + // TODO: Allow combining for several dead chars rather than only the first one. + // The framework doesn't know how to do this now. + final int deadCodePoint = mDeadSequence.codePointAt(0); + mDeadSequence.setLength(0); + final int resultingCodePoint = + KeyCharacterMap.getDeadChar(deadCodePoint, event.mCodePoint); + if (0 == resultingCodePoint) { + // We can't combine both characters. We need to commit the dead key as a committable + // character, and the next char too unless it's a space (because as a special case, + // dead key + space should result in only the dead key being committed - that's + // how dead keys work). + // If the event is a space, we should commit the dead char alone, but if it's + // not, we need to commit both. + return Event.createCommittableEvent(deadCodePoint, + Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */); + } else { + // We could combine the characters. + return Event.createCommittableEvent(resultingCodePoint, null /* next */); + } + } + } + +} diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index 215e4dee5..1f3320eb7 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -54,39 +54,40 @@ public class Event { final private static int NOT_A_CODE_POINT = 0; - private int mType; // The type of event - one of the constants above + final private int mType; // The type of event - one of the constants above // The code point associated with the event, if relevant. This is a unicode code point, and // has nothing to do with other representations of the key. It is only relevant if this event // is the right type: COMMITTABLE or DEAD or TOGGLE, but for a mode key like hankaku/zenkaku or // ctrl, there is no code point associated so this should be NOT_A_CODE_POINT to avoid // unintentional use of its value when it's not relevant. - private int mCodePoint; + final public int mCodePoint; + // The next event, if any. Null if there is no next event yet. + final public Event mNextEvent; - static Event obtainEvent() { - // TODO: create an event pool instead - return new Event(); + // This method is private - to create a new event, use one of the create* utility methods. + private Event(final int type, final int codePoint, final Event next) { + mType = type; + mCodePoint = codePoint; + mNextEvent = next; } - public void setDeadEvent(final int codePoint) { - mType = EVENT_DEAD; - mCodePoint = codePoint; + public static Event createDeadEvent(final int codePoint, final Event next) { + return new Event(EVENT_DEAD, codePoint, next); } - public void setCommittableEvent(final int codePoint) { - mType = EVENT_COMMITTABLE; - mCodePoint = codePoint; + public static Event createCommittableEvent(final int codePoint, final Event next) { + return new Event(EVENT_COMMITTABLE, codePoint, next); } - public void setNotHandledEvent() { - mType = EVENT_NOT_HANDLED; - mCodePoint = NOT_A_CODE_POINT; // Just in case + public static Event createNotHandledEvent() { + return new Event(EVENT_NOT_HANDLED, NOT_A_CODE_POINT, null); } public boolean isCommittable() { return EVENT_COMMITTABLE == mType; } - public int getCodePoint() { - return mCodePoint; + public boolean isDead() { + return EVENT_DEAD == mType; } } diff --git a/java/src/com/android/inputmethod/event/EventInterpreter.java b/java/src/com/android/inputmethod/event/EventInterpreter.java index 1bd0cca00..6efe899bb 100644 --- a/java/src/com/android/inputmethod/event/EventInterpreter.java +++ b/java/src/com/android/inputmethod/event/EventInterpreter.java @@ -19,9 +19,12 @@ package com.android.inputmethod.event; import android.util.SparseArray; import android.view.KeyEvent; +import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinIME; +import java.util.ArrayList; + /** * This class implements the logic between receiving events and generating code points. * @@ -40,6 +43,7 @@ public class EventInterpreter { final SparseArray<HardwareEventDecoder> mHardwareEventDecoders; final SoftwareEventDecoder mSoftwareEventDecoder; final LatinIME mLatinIme; + final ArrayList<Combiner> mCombiners; /** * Create a default interpreter. @@ -74,6 +78,8 @@ public class EventInterpreter { // capacity of 1. mHardwareEventDecoders = new SparseArray<HardwareEventDecoder>(1); mSoftwareEventDecoder = new SoftwareKeyboardEventDecoder(); + mCombiners = CollectionUtils.newArrayList(); + mCombiners.add(new DeadKeyCombiner()); mLatinIme = latinIme; } @@ -106,19 +112,22 @@ public class EventInterpreter { } private boolean onEvent(final Event event) { - if (event.isCommittable()) { - mLatinIme.onCodeInput(event.getCodePoint(), - Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE); - return true; + Event currentlyProcessingEvent = event; + boolean processed = false; + for (int i = 0; i < mCombiners.size(); ++i) { + currentlyProcessingEvent = mCombiners.get(i).combine(event); + } + while (null != currentlyProcessingEvent) { + if (currentlyProcessingEvent.isCommittable()) { + mLatinIme.onCodeInput(currentlyProcessingEvent.mCodePoint, + Constants.EXTERNAL_KEYBOARD_COORDINATE, + Constants.EXTERNAL_KEYBOARD_COORDINATE); + processed = true; + } else if (event.isDead()) { + processed = true; + } + currentlyProcessingEvent = currentlyProcessingEvent.mNextEvent; } - // TODO: Classify the event - input or non-input (see design doc) - // TODO: IF action event - // Send decoded action back to LatinIME - // ELSE - // Send input event to the combiner - // Get back new input material + visual feedback + combiner state - // Route the event to Latin IME - // ENDIF - return false; + return processed; } } diff --git a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java index 2dbc9f00b..2fb7fe8b4 100644 --- a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java +++ b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java @@ -38,7 +38,6 @@ public class HardwareKeyboardEventDecoder implements HardwareEventDecoder { @Override public Event decodeHardwareKey(final KeyEvent keyEvent) { - final Event event = Event.obtainEvent(); // KeyEvent#getUnicodeChar() does not exactly returns a unicode char, but rather a value // that includes both the unicode char in the lower 21 bits and flags in the upper bits, // hence the name "codePointAndFlags". {@see KeyEvent#getUnicodeChar()} for more info. @@ -48,22 +47,21 @@ public class HardwareKeyboardEventDecoder implements HardwareEventDecoder { // the key for 'A' or Space, but also Backspace or Ctrl or Caps Lock. final int keyCode = keyEvent.getKeyCode(); if (KeyEvent.KEYCODE_DEL == keyCode) { - event.setCommittableEvent(Constants.CODE_DELETE); - return event; + return Event.createCommittableEvent(Constants.CODE_DELETE, null /* next */); } if (keyEvent.isPrintingKey() || KeyEvent.KEYCODE_SPACE == keyCode || KeyEvent.KEYCODE_ENTER == keyCode) { if (0 != (codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT)) { // A dead key. - event.setDeadEvent(codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT_MASK); + return Event.createDeadEvent( + codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT_MASK, null /* next */); } else { // A committable character. This should be committed right away, taking into // account the current state. - event.setCommittableEvent(codePointAndFlags); + return Event.createCommittableEvent(codePointAndFlags, null /* next */); } } else { - event.setNotHandledEvent(); + return Event.createNotHandledEvent(); } - return event; } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 1088fdab4..bc9dbc049 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -36,6 +36,7 @@ import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; +import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SettingsValues; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.WordComposer; @@ -181,8 +182,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { keyboardView.setKeyboard(keyboard); mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding); keyboardView.setKeyPreviewPopupEnabled( - SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources), - SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); + Settings.readKeyPreviewPopupEnabled(mPrefs, mResources), + Settings.readKeyPreviewPopupDismissDelay(mPrefs, mResources)); keyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); final boolean subtypeChanged = (oldKeyboard == null) diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index b7bee3430..b7584d4cd 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -146,13 +146,17 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, // Key preview private static final int PREVIEW_ALPHA = 240; private final int mKeyPreviewLayoutId; - private final int mPreviewOffset; - private final int mPreviewHeight; - private final int mPreviewLingerTimeout; + private final int mKeyPreviewOffset; + private final int mKeyPreviewHeight; private final SparseArray<TextView> mKeyPreviewTexts = CollectionUtils.newSparseArray(); protected final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); private boolean mShowKeyPreviewPopup = true; - private int mDelayAfterPreview; + private int mKeyPreviewLingerTimeout; + + // Gesture floating preview text + // TODO: Make this parameter customizable by user via settings. + private int mGestureFloatingPreviewTextLingerTimeout; + // Background state set private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { { // STATE_MIDDLE @@ -204,6 +208,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, public static class DrawingHandler extends StaticInnerHandlerWrapper<KeyboardView> { private static final int MSG_DISMISS_KEY_PREVIEW = 0; + private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; public DrawingHandler(final KeyboardView outerInstance) { super(outerInstance); @@ -221,6 +226,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, previewText.setVisibility(INVISIBLE); } break; + case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: + keyboardView.mPreviewPlacerView.setGestureFloatingPreviewText(SuggestedWords.EMPTY); + break; } } @@ -236,6 +244,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, removeMessages(MSG_DISMISS_KEY_PREVIEW); } + public void dismissGestureFloatingPreviewText(final long delay) { + sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); + } + public void cancelAllMessages() { cancelAllDismissKeyPreviews(); } @@ -252,13 +264,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); mKeyBackground = keyboardViewAttr.getDrawable(R.styleable.KeyboardView_keyBackground); mKeyBackground.getPadding(mKeyBackgroundPadding); - mPreviewOffset = keyboardViewAttr.getDimensionPixelOffset( + mKeyPreviewOffset = keyboardViewAttr.getDimensionPixelOffset( R.styleable.KeyboardView_keyPreviewOffset, 0); - mPreviewHeight = keyboardViewAttr.getDimensionPixelSize( + mKeyPreviewHeight = keyboardViewAttr.getDimensionPixelSize( R.styleable.KeyboardView_keyPreviewHeight, 80); - mPreviewLingerTimeout = keyboardViewAttr.getInt( + mKeyPreviewLingerTimeout = keyboardViewAttr.getInt( R.styleable.KeyboardView_keyPreviewLingerTimeout, 0); - mDelayAfterPreview = mPreviewLingerTimeout; mKeyLabelHorizontalPadding = keyboardViewAttr.getDimensionPixelOffset( R.styleable.KeyboardView_keyLabelHorizontalPadding, 0); mKeyHintLetterPadding = keyboardViewAttr.getDimension( @@ -280,6 +291,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, R.styleable.KeyboardView_moreKeysLayout, 0); mBackgroundDimAlpha = keyboardViewAttr.getInt( R.styleable.KeyboardView_backgroundDimAlpha, 0); + mGestureFloatingPreviewTextLingerTimeout = keyboardViewAttr.getInt( + R.styleable.KeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); keyboardViewAttr.recycle(); final TypedArray keyAttr = context.obtainStyledAttributes(attrs, @@ -332,7 +345,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, */ public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { mShowKeyPreviewPopup = previewEnabled; - mDelayAfterPreview = delay; + mKeyPreviewLingerTimeout = delay; } /** @@ -820,7 +833,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, @Override public void dismissKeyPreview(final PointerTracker tracker) { - mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); + mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, tracker); } private void addKeyPreview(final TextView keyPreview) { @@ -878,7 +891,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, public void dismissGestureFloatingPreviewText() { locatePreviewPlacerView(); - mPreviewPlacerView.dismissGestureFloatingPreviewText(); + mDrawingHandler.dismissGestureFloatingPreviewText(mGestureFloatingPreviewTextLingerTimeout); } @Override @@ -942,7 +955,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); final int keyDrawWidth = key.getDrawWidth(); final int previewWidth = previewText.getMeasuredWidth(); - final int previewHeight = mPreviewHeight; + final int previewHeight = mKeyPreviewHeight; // The width and height of visible part of the key preview background. The content marker // of the background 9-patch have to cover the visible part of the background. previewParams.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft() @@ -951,7 +964,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, - previewText.getPaddingBottom(); // The distance between the top edge of the parent key and the bottom of the visible part // of the key preview background. - previewParams.mPreviewVisibleOffset = mPreviewOffset - previewText.getPaddingBottom(); + previewParams.mPreviewVisibleOffset = mKeyPreviewOffset - previewText.getPaddingBottom(); getLocationInWindow(mOriginCoords); // The key preview is horizontally aligned with the center of the visible part of the // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and @@ -970,7 +983,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, } // The key preview is placed vertically above the top edge of the parent key with an // arbitrary offset. - final int previewY = key.mY - previewHeight + mPreviewOffset + final int previewY = key.mY - previewHeight + mKeyPreviewOffset + CoordinateUtils.y(mOriginCoords); if (background != null) { diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 130fad851..625575d53 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -366,6 +366,11 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } @Override + public void cancelUpdateBatchInputTimer(final PointerTracker tracker) { + removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); + } + + @Override public void cancelAllUpdateBatchInputTimers() { removeMessages(MSG_UPDATE_BATCH_INPUT); } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 59a3c99aa..036372c37 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -98,6 +98,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { public boolean isInDoubleTapTimeout(); public void cancelKeyTimers(); public void startUpdateBatchInputTimer(PointerTracker tracker); + public void cancelUpdateBatchInputTimer(PointerTracker tracker); public void cancelAllUpdateBatchInputTimers(); public static class Adapter implements TimerProxy { @@ -124,6 +125,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { @Override public void startUpdateBatchInputTimer(PointerTracker tracker) {} @Override + public void cancelUpdateBatchInputTimer(PointerTracker tracker) {} + @Override public void cancelAllUpdateBatchInputTimers() {} } } @@ -791,6 +794,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private void cancelBatchInput() { sPointerTrackerQueue.cancelAllPointerTracker(); + mIsDetectingGesture = false; if (!sInGesture) { return; } @@ -916,8 +920,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final boolean isMajorEvent, final Key key) { final int gestureTime = (int)(eventTime - sGestureFirstDownTime); if (mIsDetectingGesture) { + final int beforeLength = mGestureStrokeWithPreviewPoints.getLength(); final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard( x, y, gestureTime, isMajorEvent); + if (mGestureStrokeWithPreviewPoints.getLength() > beforeLength) { + mTimerProxy.startUpdateBatchInputTimer(this); + } + // If the move event goes out from valid batch input area, cancel batch input. if (!onValidArea) { cancelBatchInput(); return; @@ -1122,6 +1131,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { printTouchEvent("onUpEvent :", x, y, eventTime); } + mTimerProxy.cancelUpdateBatchInputTimer(this); if (!sInGesture) { if (mCurrentKey != null && mCurrentKey.isModifier()) { // Before processing an up event of modifier key, all pointers already being @@ -1196,6 +1206,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element { @Override public void cancelTracking() { + if (isShowingMoreKeysPanel()) { + return; + } mIsTrackingCanceled = true; } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java index 84cfb389c..aed23a4db 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java @@ -19,7 +19,6 @@ package com.android.inputmethod.keyboard.internal; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Rect; @@ -40,7 +39,6 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview { private static final class GesturePreviewTextParams { public final int mGesturePreviewTextSize; public final int mGesturePreviewTextColor; - public final int mGesturePreviewTextDimmedColor; public final int mGesturePreviewTextOffset; public final int mGesturePreviewTextHeight; public final int mGesturePreviewColor; @@ -66,7 +64,6 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview { R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); mGesturePreviewRoundRadius = keyboardViewAttr.getDimension( R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); - mGesturePreviewTextDimmedColor = Color.GRAY; final Paint textPaint = new Paint(); textPaint.setAntiAlias(true); @@ -103,11 +100,7 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview { } public void setSuggetedWords(final SuggestedWords suggestedWords) { - if (suggestedWords == null) { - mSuggestedWords = SuggestedWords.EMPTY; - } else { - mSuggestedWords = suggestedWords; - } + mSuggestedWords = suggestedWords; updatePreviewPosition(); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index a43e94a75..ea03f1bd7 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -163,6 +163,10 @@ public class GestureStroke { } } + public int getLength() { + return mEventTimes.getLength(); + } + public void onDownEvent(final int x, final int y, final long downTime, final long gestureFirstDownTime, final long lastTypingTime) { reset(); @@ -202,7 +206,7 @@ public class GestureStroke { if (!hasDetectedFastMove()) { return false; } - final int size = mEventTimes.getLength(); + final int size = getLength(); if (size <= 0) { return false; } @@ -229,10 +233,14 @@ public class GestureStroke { } public void duplicateLastPointWith(final int time) { - final int lastIndex = mEventTimes.getLength() - 1; + final int lastIndex = getLength() - 1; if (lastIndex >= 0) { final int x = mXCoordinates.get(lastIndex); final int y = mYCoordinates.get(lastIndex); + if (DEBUG) { + Log.d(TAG, String.format("[%d] duplicateLastPointWith: %d,%d|%d", mPointerId, + x, y, time)); + } // TODO: Have appendMajorPoint() appendPoint(x, y, time); updateIncrementalRecognitionSize(x, y, time); @@ -251,6 +259,16 @@ public class GestureStroke { } private void appendPoint(final int x, final int y, final int time) { + final int lastIndex = getLength() - 1; + // The point that is created by {@link duplicateLastPointWith(int)} may have later event + // time than the next {@link MotionEvent}. To maintain the monotonicity of the event time, + // drop the successive point here. + if (lastIndex >= 0 && mEventTimes.get(lastIndex) > time) { + Log.w(TAG, String.format("[%d] drop stale event: %d,%d|%d last: %d,%d|%d", mPointerId, + x, y, time, mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex), + mEventTimes.get(lastIndex))); + return; + } mEventTimes.add(time); mXCoordinates.add(x); mYCoordinates.add(y); @@ -267,7 +285,7 @@ public class GestureStroke { } private int detectFastMove(final int x, final int y, final int time) { - final int size = mEventTimes.getLength(); + final int size = getLength(); final int lastIndex = size - 1; final int lastX = mXCoordinates.get(lastIndex); final int lastY = mYCoordinates.get(lastIndex); @@ -307,7 +325,7 @@ public class GestureStroke { */ public boolean addPointOnKeyboard(final int x, final int y, final int time, final boolean isMajorEvent) { - final int size = mEventTimes.getLength(); + final int size = getLength(); if (size <= 0) { // Down event appendPoint(x, y, time); @@ -334,7 +352,7 @@ public class GestureStroke { final int pixelsPerSec = pixels * MSEC_PER_SEC; // Equivalent to (pixels / msecs < mGestureRecognitionThreshold / MSEC_PER_SEC) if (pixelsPerSec < mGestureRecognitionSpeedThreshold * msecs) { - mIncrementalRecognitionSize = mEventTimes.getLength(); + mIncrementalRecognitionSize = getLength(); } } @@ -344,7 +362,7 @@ public class GestureStroke { } public final void appendAllBatchPoints(final InputPointers out) { - appendBatchPoints(out, mEventTimes.getLength()); + appendBatchPoints(out, getLength()); } public final void appendIncrementalBatchPoints(final InputPointers out) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index a005dc975..bfb7b1fe0 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -41,6 +41,7 @@ import com.android.inputmethod.latin.SuggestedWords; public final class PreviewPlacerView extends RelativeLayout { private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance(); + // TODO: Consolidate gesture preview trail with {@link KeyboardView} private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails = CollectionUtils.newSparseArray(); private final Params mGesturePreviewTrailParams; @@ -60,19 +61,16 @@ public final class PreviewPlacerView extends RelativeLayout { private final DrawingHandler mDrawingHandler; + // TODO: Remove drawing handler. private static final class DrawingHandler extends StaticInnerHandlerWrapper<PreviewPlacerView> { - private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 0; - private static final int MSG_UPDATE_GESTURE_PREVIEW_TRAIL = 1; + private static final int MSG_UPDATE_GESTURE_PREVIEW_TRAIL = 0; private final Params mGesturePreviewTrailParams; - private final int mGestureFloatingPreviewTextLingerTimeout; public DrawingHandler(final PreviewPlacerView outerInstance, - final Params gesturePreviewTrailParams, - final int getstureFloatinPreviewTextLinerTimeout) { + final Params gesturePreviewTrailParams) { super(outerInstance); mGesturePreviewTrailParams = gesturePreviewTrailParams; - mGestureFloatingPreviewTextLingerTimeout = getstureFloatinPreviewTextLinerTimeout; } @Override @@ -80,21 +78,12 @@ public final class PreviewPlacerView extends RelativeLayout { final PreviewPlacerView placerView = getOuterInstance(); if (placerView == null) return; switch (msg.what) { - case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: - placerView.setGestureFloatingPreviewText(null); - break; case MSG_UPDATE_GESTURE_PREVIEW_TRAIL: placerView.invalidate(); break; } } - public void dismissGestureFloatingPreviewText() { - removeMessages(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT); - sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), - mGestureFloatingPreviewTextLingerTimeout); - } - public void postUpdateGestureTrailPreview() { removeMessages(MSG_UPDATE_GESTURE_PREVIEW_TRAIL); sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_PREVIEW_TRAIL), @@ -112,16 +101,13 @@ public final class PreviewPlacerView extends RelativeLayout { final TypedArray keyboardViewAttr = context.obtainStyledAttributes( attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - final int gestureFloatingPreviewTextLingerTimeout = keyboardViewAttr.getInt( - R.styleable.KeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); // TODO: mGestureFloatingPreviewText could be an instance of GestureFloatingPreviewText or // MultiGesturePreviewText, depending on the user's choice in the settings. mGestureFloatingPreviewText = new GestureFloatingPreviewText(keyboardViewAttr, context); mGesturePreviewTrailParams = new Params(keyboardViewAttr); keyboardViewAttr.recycle(); - mDrawingHandler = new DrawingHandler(this, mGesturePreviewTrailParams, - gestureFloatingPreviewTextLingerTimeout); + mDrawingHandler = new DrawingHandler(this, mGesturePreviewTrailParams); final Paint gesturePaint = new Paint(); gesturePaint.setAntiAlias(true); @@ -285,10 +271,6 @@ public final class PreviewPlacerView extends RelativeLayout { invalidate(); } - public void dismissGestureFloatingPreviewText() { - mDrawingHandler.dismissGestureFloatingPreviewText(); - } - private void drawSlidingKeyInputPreview(final Canvas canvas) { // TODO: Implement rubber band preview } diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java index 6ac5a9b94..a7e85e40c 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -400,7 +400,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { mKeyboardLayoutSetAdapter = new KeyboardLayoutSetAdapter(context); final String prefSubtypes = - SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources()); + Settings.readPrefAdditionalSubtypes(mPrefs, getResources()); setPrefSubtypes(prefSubtypes, context); mIsAddingNewSubtype = (savedInstanceState != null) @@ -564,19 +564,13 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { @Override public void onPause() { super.onPause(); - final String oldSubtypes = SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources()); + final String oldSubtypes = Settings.readPrefAdditionalSubtypes(mPrefs, getResources()); final InputMethodSubtype[] subtypes = getSubtypes(); final String prefSubtypes = AdditionalSubtype.createPrefSubtypes(subtypes); if (prefSubtypes.equals(oldSubtypes)) { return; } - - final SharedPreferences.Editor editor = mPrefs.edit(); - try { - editor.putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes); - } finally { - editor.apply(); - } + Settings.writePrefAdditionalSubtypes(mPrefs, prefSubtypes); mRichImm.setAdditionalInputMethodSubtypes(subtypes); } diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java index 6367156ef..8a1613120 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -102,7 +102,7 @@ public final class AudioAndHapticFeedbackManager { sound = AudioManager.FX_KEYPRESS_STANDARD; break; } - mAudioManager.playSoundEffect(sound, mSettingsValues.mFxVolume); + mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 6eeee9c2a..df733c55a 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1083,7 +1083,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public boolean onEvaluateFullscreenMode() { // Reread resource value here, because this method is called by framework anytime as needed. final boolean isFullscreenModeAllowed = - SettingsValues.isFullscreenModeAllowed(getResources()); + Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI // implies NO_FULLSCREEN. However, the framework mistakenly does. i.e. NO_EXTRACT_UI @@ -1131,7 +1131,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.getInstance().onWordFinished(typedWord); + ResearchLogger.getInstance().onWordFinished(typedWord, mWordComposer.isBatchMode()); } } } @@ -1163,7 +1163,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } private void swapSwapperAndSpace() { - CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); + final CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Constants.CODE_SPACE) { @@ -1171,7 +1171,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final String text = lastTwo.charAt(1) + " "; mConnection.commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_swapSwapperAndSpace(text); + ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); } mKeyboardSwitcher.updateShiftState(); } @@ -1191,7 +1191,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final String textToInsert = ". "; mConnection.commitText(textToInsert, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert); + ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert, + false /* isBatchMode */); } mKeyboardSwitcher.updateShiftState(); return true; @@ -1440,7 +1441,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mConnection.commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_onTextInput(text); + ResearchLogger.latinIME_onTextInput(text, false /* isBatchMode */); } mConnection.endBatchEdit(); // Space state must be updated before calling updateShiftState @@ -1587,10 +1588,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final boolean dismissGestureFloatingPreviewText) { showSuggestionStrip(suggestedWords, null); final KeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); + mainKeyboardView.showGestureFloatingPreviewText(suggestedWords); if (dismissGestureFloatingPreviewText) { mainKeyboardView.dismissGestureFloatingPreviewText(); - } else { - mainKeyboardView.showGestureFloatingPreviewText(suggestedWords); } } @@ -1665,10 +1665,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final int length = mWordComposer.size(); if (length > 0) { if (mWordComposer.isBatchMode()) { - mWordComposer.reset(); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_handleBackspace_batch(mWordComposer.getTypedWord()); + final String word = mWordComposer.getTypedWord(); + ResearchLogger.latinIME_handleBackspace_batch(word); + ResearchLogger.getInstance().uncommitCurrentLogUnit( + word, false /* dumpCurrentLogUnit */); } + mWordComposer.reset(); } else { mWordComposer.deleteLast(); } @@ -1717,6 +1720,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // If there is a selection, remove it. final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); + // Reset mLastSelectionEnd to mLastSelectionStart. This is what is supposed to + // happen, and if it's wrong, the next call to onUpdateSelection will correct it, + // but we want to set it right away to avoid it being used with the wrong values + // later (typically, in a subsequent press on backspace). + mLastSelectionEnd = mLastSelectionStart; mConnection.deleteSurroundingText(lengthToDelete, 0); } else { // There is no selection, just delete one character. @@ -2079,7 +2087,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, - separatorString); + separatorString, mWordComposer.isBatchMode()); } mExpectingUpdateSelection = true; commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, @@ -2113,7 +2121,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction onCodeInput(primaryCode, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_punctuationSuggestion(index, suggestion); + ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, + false /* isBatchMode */); } return; } @@ -2152,7 +2161,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion); + ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, + mWordComposer.isBatchMode()); } mConnection.endBatchEdit(); // Don't allow cancellation of manual pick @@ -2249,6 +2259,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mConnection.getWordBeforeCursorIfAtEndOfWord(mSettings.getCurrent()); if (null != word) { restartSuggestionsOnWordBeforeCursor(word); + // TODO: Handle the case where the user manually moves the cursor and then backs up over + // a separator. In that case, the current log unit should not be uncommitted. + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().uncommitCurrentLogUnit(word.toString(), + true /* dumpCurrentLogUnit */); + } } } @@ -2292,7 +2308,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); } if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord); + ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord, + mWordComposer.isBatchMode()); } // Don't restart suggestion yet. We'll restart if the user deletes the // separator. diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 0d3ebacb1..f7268fc33 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -648,19 +648,20 @@ public final class RichInputConnection { // Here we test whether we indeed have a period and a space before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0); - if (!". ".equals(textBeforeCursor)) { + final String periodSpace = ". "; + if (!periodSpace.equals(textBeforeCursor)) { // Theoretically we should not be coming here if there isn't ". " before the // cursor, but the application may be changing the text while we are typing, so // anything goes. We should not crash. Log.d(TAG, "Tried to revert double-space combo but we didn't find " - + "\". \" just before the cursor."); + + "\"" + periodSpace + "\" just before the cursor."); return false; } deleteSurroundingText(2, 0); final String doubleSpace = " "; commitText(doubleSpace, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.richInputConnection_revertDoubleSpacePeriod(doubleSpace); + ResearchLogger.richInputConnection_revertDoubleSpacePeriod(); } return true; } @@ -685,7 +686,7 @@ public final class RichInputConnection { final String text = " " + textBeforeCursor.subSequence(0, 1); commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.richInputConnection_revertSwapPunctuation(text); + ResearchLogger.richInputConnection_revertSwapPunctuation(); } return true; } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 637916f76..e39aae958 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -75,7 +75,7 @@ public final class RichInputMethodManager { // Initialize additional subtypes. SubtypeLocale.init(context); - final String prefAdditionalSubtypes = SettingsValues.getPrefAdditionalSubtypes( + final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes( prefs, context.getResources()); final InputMethodSubtype[] additionalSubtypes = AdditionalSubtype.createAdditionalSubtypesArray(prefAdditionalSubtypes); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 1d9d85b47..c5930a935 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -23,6 +23,7 @@ import android.preference.PreferenceManager; import com.android.inputmethod.latin.LocaleUtils.RunInLocale; +import java.util.HashMap; import java.util.Locale; public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -66,6 +67,11 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; public static final String PREF_DEBUG_SETTINGS = "debug_settings"; + // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead. + // This is being used only for the backward compatibility. + private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = + "pref_suppress_language_switch_key"; + private Resources mRes; private SharedPreferences mPrefs; private Locale mCurrentLocale; @@ -116,4 +122,92 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public SettingsValues getCurrent() { return mSettingsValues; } + + // Accessed from the settings interface, hence public + public static boolean readKeyPreviewPopupEnabled(final SharedPreferences prefs, + final Resources res) { + final boolean showPopupOption = res.getBoolean( + R.bool.config_enable_show_popup_on_keypress_option); + if (!showPopupOption) return res.getBoolean(R.bool.config_default_popup_preview); + return prefs.getBoolean(PREF_POPUP_ON, + res.getBoolean(R.bool.config_default_popup_preview)); + } + + public static int readKeyPreviewPopupDismissDelay(final SharedPreferences prefs, + final Resources res) { + return Integer.parseInt(prefs.getString(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + Integer.toString(res.getInteger( + R.integer.config_key_preview_linger_timeout)))); + } + + public static boolean readShowsLanguageSwitchKey(final SharedPreferences prefs) { + if (prefs.contains(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) { + final boolean suppressLanguageSwitchKey = prefs.getBoolean( + PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); + final SharedPreferences.Editor editor = prefs.edit(); + editor.remove(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY); + editor.putBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, !suppressLanguageSwitchKey); + editor.apply(); + } + return prefs.getBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, true); + } + + public static String readPrefAdditionalSubtypes(final SharedPreferences prefs, + final Resources res) { + final String predefinedPrefSubtypes = AdditionalSubtype.createPrefSubtypes( + res.getStringArray(R.array.predefined_subtypes)); + return prefs.getString(PREF_CUSTOM_INPUT_STYLES, predefinedPrefSubtypes); + } + + public static void writePrefAdditionalSubtypes(final SharedPreferences prefs, + final String prefSubtypes) { + prefs.edit().putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply(); + } + + public static float readKeypressSoundVolume(final SharedPreferences prefs, + final Resources res) { + final float volume = prefs.getFloat(PREF_KEYPRESS_SOUND_VOLUME, -1.0f); + if (volume >= 0) { + return volume; + } + return Float.parseFloat( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); + } + + public static int readVibrationDuration(final SharedPreferences prefs, + final Resources res) { + final int ms = prefs.getInt(PREF_VIBRATION_DURATION_SETTINGS, -1); + if (ms >= 0) { + return ms; + } + return Integer.parseInt( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations)); + } + + public static boolean readUsabilityStudyMode(final SharedPreferences prefs) { + return prefs.getBoolean(DebugSettings.PREF_USABILITY_STUDY_MODE, true); + } + + public static long readLastUserHistoryWriteTime(final SharedPreferences prefs, + final String locale) { + final String str = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); + final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(str); + if (map.containsKey(locale)) { + return map.get(locale); + } + return 0; + } + + public static void writeLastUserHistoryWriteTime(final SharedPreferences prefs, + final String locale) { + final String oldStr = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); + final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(oldStr); + map.put(locale, System.currentTimeMillis()); + final String newStr = LocaleUtils.localeAndTimeHashMapToStr(map); + prefs.edit().putString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply(); + } + + public static boolean readUseFullscreenMode(final Resources res) { + return res.getBoolean(R.bool.config_use_fullscreen_mode); + } } diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java index a2980bfa2..507a37b7c 100644 --- a/java/src/com/android/inputmethod/latin/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -145,11 +145,11 @@ public final class SettingsFragment extends InputMethodSettingsFragment mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); } mKeyPreviewPopupDismissDelay.setEnabled( - SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); + Settings.readKeyPreviewPopupEnabled(prefs, res)); } setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, - SettingsValues.showsLanguageSwitchKey(prefs)); + Settings.readShowsLanguageSwitchKey(prefs)); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); @@ -180,7 +180,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment }); mKeypressVibrationDurationSettingsPref.setSummary( res.getString(R.string.settings_keypress_vibration_duration, - SettingsValues.getCurrentVibrationDuration(prefs, res))); + Settings.readVibrationDuration(prefs, res))); } mKeypressSoundVolumeSettingsPref = @@ -229,7 +229,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment prefs.getBoolean(Settings.PREF_POPUP_ON, true)); } else if (key.equals(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY)) { setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, - SettingsValues.showsLanguageSwitchKey(prefs)); + Settings.readShowsLanguageSwitchKey(prefs)); } else if (key.equals(Settings.PREF_GESTURE_INPUT)) { final boolean gestureInputEnabledByConfig = getResources().getBoolean( R.bool.config_gesture_input_enabled_by_build_config); @@ -261,7 +261,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES); final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); final Resources res = getResources(); - final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res); + final String prefSubtype = Settings.readPrefAdditionalSubtypes(prefs, res); final InputMethodSubtype[] subtypes = AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); final StringBuilder styles = new StringBuilder(); @@ -323,7 +323,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment AudioAndHapticFeedbackManager.getInstance().vibrate(ms); } }; - final int currentMs = SettingsValues.getCurrentVibrationDuration(sp, getResources()); + final int currentMs = Settings.readVibrationDuration(sp, getResources()); final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); builder.setTitle(R.string.prefs_keypress_vibration_duration_settings) .setListener(listener) @@ -339,7 +339,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment private static int getCurrentKeyPressSoundVolumePercent(final SharedPreferences sp, final Resources res) { - return (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * PERCENT_FLOAT); + return (int)(Settings.readKeypressSoundVolume(sp, res) * PERCENT_FLOAT); } private void showKeypressSoundVolumeSettingDialog() { diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 39406621c..9a2024618 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -27,7 +27,6 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; /** * When you call the constructor of this class, you may want to change the current system locale by @@ -36,19 +35,6 @@ import java.util.HashMap; public final class SettingsValues { private static final String TAG = SettingsValues.class.getSimpleName(); - private static final int SUGGESTION_VISIBILITY_SHOW_VALUE - = R.string.prefs_suggestion_visibility_show_value; - private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE - = R.string.prefs_suggestion_visibility_show_only_portrait_value; - private static final int SUGGESTION_VISIBILITY_HIDE_VALUE - = R.string.prefs_suggestion_visibility_hide_value; - - private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] { - SUGGESTION_VISIBILITY_SHOW_VALUE, - SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE, - SUGGESTION_VISIBILITY_HIDE_VALUE - }; - // From resources: public final int mDelayUpdateOldSuggestions; public final String mWeakSpaceStrippers; @@ -65,14 +51,8 @@ public final class SettingsValues { public final boolean mSoundOn; public final boolean mKeyPreviewPopupOn; private final String mVoiceMode; - private final String mAutoCorrectionThresholdRawValue; - public final String mShowSuggestionsSetting; - @SuppressWarnings("unused") // TODO: Use this - private final boolean mUsabilityStudyMode; public final boolean mIncludesOtherImesInLanguageSwitchList; public final boolean mShowsLanguageSwitchKey; - @SuppressWarnings("unused") // TODO: Use this - private final String mKeyPreviewPopupDismissDelayRawValue; public final boolean mUseContactsDict; public final boolean mUseDoubleSpacePeriod; // Use bigrams to predict the next word when there is no input for it yet @@ -86,7 +66,7 @@ public final class SettingsValues { // Deduced settings public final int mKeypressVibrationDuration; - public final float mFxVolume; + public final float mKeypressSoundVolume; public final int mKeyPreviewPopupDismissDelay; private final boolean mAutoCorrectEnabled; public final float mAutoCorrectionThreshold; @@ -129,35 +109,30 @@ public final class SettingsValues { // Get the settings preferences mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); - mVibrateOn = isVibrateOn(prefs, res); + mVibrateOn = readVibrationEnabled(prefs, res); mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); - mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); + mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res); final String voiceModeMain = res.getString(R.string.voice_mode_main); final String voiceModeOff = res.getString(R.string.voice_mode_off); mVoiceMode = prefs.getString(Settings.PREF_VOICE_MODE, voiceModeMain); - mAutoCorrectionThresholdRawValue = prefs.getString(Settings.PREF_AUTO_CORRECTION_THRESHOLD, + final String autoCorrectionThresholdRawValue = prefs.getString( + Settings.PREF_AUTO_CORRECTION_THRESHOLD, res.getString(R.string.auto_correction_threshold_mode_index_modest)); - mShowSuggestionsSetting = prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING, - res.getString(R.string.prefs_suggestion_visibility_default_value)); - mUsabilityStudyMode = getUsabilityStudyMode(prefs); mIncludesOtherImesInLanguageSwitchList = prefs.getBoolean( Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false); - mShowsLanguageSwitchKey = showsLanguageSwitchKey(prefs); - mKeyPreviewPopupDismissDelayRawValue = prefs.getString( - Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, - Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout))); + mShowsLanguageSwitchKey = Settings.readShowsLanguageSwitchKey(prefs); mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); - mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue); - mBigramPredictionEnabled = isBigramPredictionEnabled(prefs, res); + mAutoCorrectEnabled = readAutoCorrectEnabled(res, autoCorrectionThresholdRawValue); + mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); // Compute other readable settings - mKeypressVibrationDuration = getCurrentVibrationDuration(prefs, res); - mFxVolume = getCurrentKeypressSoundVolume(prefs, res); - mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res); - mAutoCorrectionThreshold = getAutoCorrectionThreshold(res, - mAutoCorrectionThresholdRawValue); + mKeypressVibrationDuration = Settings.readVibrationDuration(prefs, res); + mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res); + mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res); + mAutoCorrectionThreshold = readAutoCorrectionThreshold(res, + autoCorrectionThresholdRawValue); mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff); mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain); final boolean gestureInputEnabledByBuildConfig = res.getBoolean( @@ -168,53 +143,10 @@ public final class SettingsValues { mGestureFloatingPreviewTextEnabled = prefs.getBoolean( Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; - mSuggestionVisibility = createSuggestionVisibility(res); - } - - // Helper functions to create member values. - private static SuggestedWords createSuggestPuncList(final String[] puncs) { - final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList(); - if (puncs != null) { - for (final String puncSpec : puncs) { - puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec), - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED, - Dictionary.TYPE_HARDCODED)); - } - } - return new SuggestedWords(puncList, - false /* typedWordValid */, - false /* hasAutoCorrectionCandidate */, - true /* isPunctuationSuggestions */, - false /* isObsoleteSuggestions */, - false /* isPrediction */); - } - - private static String createWordSeparators(final String weakSpaceStrippers, - final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators, - final Resources res) { - String wordSeparators = weakSpaceStrippers + weakSpaceSwappers - + res.getString(R.string.phantom_space_promoting_symbols); - for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) { - wordSeparators = wordSeparators.replace( - symbolsExcludedFromWordSeparators.substring(i, i + 1), ""); - } - return wordSeparators; - } - - private int createSuggestionVisibility(final Resources res) { - final String suggestionVisiblityStr = mShowSuggestionsSetting; - for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { - if (suggestionVisiblityStr.equals(res.getString(visibility))) { - return visibility; - } - } - throw new RuntimeException("Bug: visibility string is not configured correctly"); - } - - private static boolean isVibrateOn(final SharedPreferences prefs, final Resources res) { - final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator(); - return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, - res.getBoolean(R.bool.config_default_vibration_enabled)); + final String showSuggestionsSetting = prefs.getString( + Settings.PREF_SHOW_SUGGESTIONS_SETTING, + res.getString(R.string.prefs_suggestion_visibility_default_value)); + mSuggestionVisibility = createSuggestionVisibility(res, showSuggestionsSetting); } public boolean isApplicationSpecifiedCompletionsOn() { @@ -262,63 +194,6 @@ public final class SettingsValues { return mInputAttributes.mShouldInsertSpacesAutomatically; } - private static boolean isAutoCorrectEnabled(final Resources res, - final String currentAutoCorrectionSetting) { - final String autoCorrectionOff = res.getString( - R.string.auto_correction_threshold_mode_index_off); - return !currentAutoCorrectionSetting.equals(autoCorrectionOff); - } - - // TODO: Clean up and move public helper methods to Settings class. - // Public to access from KeyboardSwitcher. Should it have access to some - // process-global instance instead? - public static boolean isKeyPreviewPopupEnabled(final SharedPreferences prefs, - final Resources res) { - final boolean showPopupOption = res.getBoolean( - R.bool.config_enable_show_popup_on_keypress_option); - if (!showPopupOption) return res.getBoolean(R.bool.config_default_popup_preview); - return prefs.getBoolean(Settings.PREF_POPUP_ON, - res.getBoolean(R.bool.config_default_popup_preview)); - } - - // Likewise - public static int getKeyPreviewPopupDismissDelay(final SharedPreferences prefs, - final Resources res) { - // TODO: use mKeyPreviewPopupDismissDelayRawValue instead of reading it again here. - return Integer.parseInt(prefs.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, - Integer.toString(res.getInteger( - R.integer.config_key_preview_linger_timeout)))); - } - - private static boolean isBigramPredictionEnabled(final SharedPreferences prefs, - final Resources res) { - return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( - R.bool.config_default_next_word_prediction)); - } - - private static float getAutoCorrectionThreshold(final Resources res, - final String currentAutoCorrectionSetting) { - final String[] autoCorrectionThresholdValues = res.getStringArray( - R.array.auto_correction_threshold_values); - // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. - float autoCorrectionThreshold = Float.MAX_VALUE; - try { - final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); - if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { - autoCorrectionThreshold = Float.parseFloat( - autoCorrectionThresholdValues[arrayIndex]); - } - } catch (NumberFormatException e) { - // Whenever the threshold settings are correct, never come here. - autoCorrectionThreshold = Float.MAX_VALUE; - Log.w(TAG, "Cannot load auto correction threshold setting." - + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting - + ", autoCorrectionThresholdValues: " - + Arrays.toString(autoCorrectionThresholdValues)); - } - return autoCorrectionThreshold; - } - public boolean isVoiceKeyEnabled(final EditorInfo editorInfo) { final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; @@ -330,23 +205,6 @@ public final class SettingsValues { return mVoiceKeyOnMain; } - // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead. - // This is being used only for the backward compatibility. - private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = - "pref_suppress_language_switch_key"; - - public static boolean showsLanguageSwitchKey(final SharedPreferences prefs) { - if (prefs.contains(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) { - final boolean suppressLanguageSwitchKey = prefs.getBoolean( - PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); - final SharedPreferences.Editor editor = prefs.edit(); - editor.remove(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY); - editor.putBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, !suppressLanguageSwitchKey); - editor.apply(); - } - return prefs.getBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, true); - } - public boolean isLanguageSwitchKeyEnabled() { if (!mShowsLanguageSwitchKey) { return false; @@ -359,65 +217,102 @@ public final class SettingsValues { } } - public static boolean isFullscreenModeAllowed(final Resources res) { - return res.getBoolean(R.bool.config_use_fullscreen_mode); + public boolean isSameInputType(final EditorInfo editorInfo) { + return mInputAttributes.isSameInputType(editorInfo); } - public static String getPrefAdditionalSubtypes(final SharedPreferences prefs, - final Resources res) { - final String predefinedPrefSubtypes = AdditionalSubtype.createPrefSubtypes( - res.getStringArray(R.array.predefined_subtypes)); - return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, predefinedPrefSubtypes); + // Helper functions to create member values. + private static SuggestedWords createSuggestPuncList(final String[] puncs) { + final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList(); + if (puncs != null) { + for (final String puncSpec : puncs) { + puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec), + SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED, + Dictionary.TYPE_HARDCODED)); + } + } + return new SuggestedWords(puncList, + false /* typedWordValid */, + false /* hasAutoCorrectionCandidate */, + true /* isPunctuationSuggestions */, + false /* isObsoleteSuggestions */, + false /* isPrediction */); } - // Accessed from the settings interface, hence public - public static float getCurrentKeypressSoundVolume(final SharedPreferences prefs, + private static String createWordSeparators(final String weakSpaceStrippers, + final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators, final Resources res) { - final float volume = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); - if (volume >= 0) { - return volume; + String wordSeparators = weakSpaceStrippers + weakSpaceSwappers + + res.getString(R.string.phantom_space_promoting_symbols); + for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) { + wordSeparators = wordSeparators.replace( + symbolsExcludedFromWordSeparators.substring(i, i + 1), ""); } - return Float.parseFloat( - ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); + return wordSeparators; } - // Likewise - public static int getCurrentVibrationDuration(final SharedPreferences prefs, - final Resources res) { - final int ms = prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); - if (ms >= 0) { - return ms; + private static final int SUGGESTION_VISIBILITY_SHOW_VALUE = + R.string.prefs_suggestion_visibility_show_value; + private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE = + R.string.prefs_suggestion_visibility_show_only_portrait_value; + private static final int SUGGESTION_VISIBILITY_HIDE_VALUE = + R.string.prefs_suggestion_visibility_hide_value; + private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] { + SUGGESTION_VISIBILITY_SHOW_VALUE, + SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE, + SUGGESTION_VISIBILITY_HIDE_VALUE + }; + + private static int createSuggestionVisibility(final Resources res, + final String suggestionVisiblityStr) { + for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { + if (suggestionVisiblityStr.equals(res.getString(visibility))) { + return visibility; + } } - return Integer.parseInt( - ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations)); + throw new RuntimeException("Bug: visibility string is not configured correctly"); } - // Likewise - public static boolean getUsabilityStudyMode(final SharedPreferences prefs) { - // TODO: use mUsabilityStudyMode instead of reading it again here - return prefs.getBoolean(DebugSettings.PREF_USABILITY_STUDY_MODE, true); + private static boolean readVibrationEnabled(final SharedPreferences prefs, + final Resources res) { + final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator(); + return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, + res.getBoolean(R.bool.config_default_vibration_enabled)); } - public static long getLastUserHistoryWriteTime(final SharedPreferences prefs, - final String locale) { - final String str = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); - final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(str); - if (map.containsKey(locale)) { - return map.get(locale); - } - return 0; + private static boolean readAutoCorrectEnabled(final Resources res, + final String currentAutoCorrectionSetting) { + final String autoCorrectionOff = res.getString( + R.string.auto_correction_threshold_mode_index_off); + return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } - public static void setLastUserHistoryWriteTime(final SharedPreferences prefs, - final String locale) { - final String oldStr = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); - final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(oldStr); - map.put(locale, System.currentTimeMillis()); - final String newStr = LocaleUtils.localeAndTimeHashMapToStr(map); - prefs.edit().putString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply(); + private static boolean readBigramPredictionEnabled(final SharedPreferences prefs, + final Resources res) { + return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( + R.bool.config_default_next_word_prediction)); } - public boolean isSameInputType(final EditorInfo editorInfo) { - return mInputAttributes.isSameInputType(editorInfo); + private static float readAutoCorrectionThreshold(final Resources res, + final String currentAutoCorrectionSetting) { + final String[] autoCorrectionThresholdValues = res.getStringArray( + R.array.auto_correction_threshold_values); + // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. + float autoCorrectionThreshold = Float.MAX_VALUE; + try { + final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); + if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { + autoCorrectionThreshold = Float.parseFloat( + autoCorrectionThresholdValues[arrayIndex]); + } + } catch (NumberFormatException e) { + // Whenever the threshold settings are correct, never come here. + autoCorrectionThreshold = Float.MAX_VALUE; + Log.w(TAG, "Cannot load auto correction threshold setting." + + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting + + ", autoCorrectionThresholdValues: " + + Arrays.toString(autoCorrectionThresholdValues)); + } + return autoCorrectionThreshold; } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index fe2908428..eb0ec3990 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -31,6 +31,7 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.KeyboardSwitcher; import java.util.List; @@ -239,7 +240,14 @@ public final class SubtypeSwitcher { return mNeedsToDisplayLanguage.getValue(); } + private static Locale sForcedLocaleForTesting = null; + @UsedForTesting + void forceLocale(final Locale locale) { + sForcedLocaleForTesting = locale; + } + public Locale getCurrentSubtypeLocale() { + if (null != sForcedLocaleForTesting) return sForcedLocaleForTesting; return SubtypeLocale.getSubtypeLocale(getCurrentSubtype()); } diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 31a0f83f1..4c7884836 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -219,7 +219,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary { } catch (InterruptedException e) { } } - final long last = SettingsValues.getLastUserHistoryWriteTime(mPrefs, mLocale); + final long last = Settings.readLastUserHistoryWriteTime(mPrefs, mLocale); final boolean initializing = last == 0; final long now = System.currentTimeMillis(); profTotal = 0; @@ -355,7 +355,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary { } // Save the timestamp after we finish writing the binary dictionary. - SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale); + Settings.writeLastUserHistoryWriteTime(mPrefs, mLocale); if (PROFILE_SAVE_RESTORE) { final long diff = System.currentTimeMillis() - now; Log.w(TAG, "PROF: Write User HistoryDictionary: " + mLocale + ", " + diff + "ms."); diff --git a/java/src/com/android/inputmethod/research/FixedLogBuffer.java b/java/src/com/android/inputmethod/research/FixedLogBuffer.java index f3302d856..9613c2db2 100644 --- a/java/src/com/android/inputmethod/research/FixedLogBuffer.java +++ b/java/src/com/android/inputmethod/research/FixedLogBuffer.java @@ -72,6 +72,15 @@ public class FixedLogBuffer extends LogBuffer { mNumActualWords++; // Must be a word, or we wouldn't be here. } + @Override + public LogUnit unshiftIn() { + final LogUnit logUnit = super.unshiftIn(); + if (logUnit != null && logUnit.hasWord()) { + mNumActualWords--; + } + return logUnit; + } + private void shiftOutThroughFirstWord() { final LinkedList<LogUnit> logUnits = getLogUnits(); while (!logUnits.isEmpty()) { diff --git a/java/src/com/android/inputmethod/research/LogBuffer.java b/java/src/com/android/inputmethod/research/LogBuffer.java index 14e8d08a2..9d095f8ad 100644 --- a/java/src/com/android/inputmethod/research/LogBuffer.java +++ b/java/src/com/android/inputmethod/research/LogBuffer.java @@ -46,6 +46,20 @@ public class LogBuffer { mLogUnits.add(logUnit); } + public LogUnit unshiftIn() { + if (mLogUnits.isEmpty()) { + return null; + } + return mLogUnits.removeLast(); + } + + public LogUnit peekLastLogUnit() { + if (mLogUnits.isEmpty()) { + return null; + } + return mLogUnits.peekLast(); + } + public boolean isEmpty() { return mLogUnits.isEmpty(); } diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java index bcb144f5f..ef2c4ea29 100644 --- a/java/src/com/android/inputmethod/research/LogUnit.java +++ b/java/src/com/android/inputmethod/research/LogUnit.java @@ -240,6 +240,7 @@ import java.util.Map; public LogUnit splitByTime(final long maxTime) { // Assume that mTimeList is in sorted order. final int length = mTimeList.size(); + // TODO: find time by binary search, e.g. using Collections#binarySearch() for (int index = 0; index < length; index++) { if (mTimeList.get(index) > maxTime) { final List<LogStatement> laterLogStatements = @@ -267,4 +268,13 @@ import java.util.Map; } return new LogUnit(); } + + public void append(final LogUnit logUnit) { + mLogStatementList.addAll(logUnit.mLogStatementList); + mValuesList.addAll(logUnit.mValuesList); + mTimeList.addAll(logUnit.mTimeList); + mWord = null; + mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit; + mIsPartOfMegaword = false; + } } diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java index bec21d7e0..898a042d6 100644 --- a/java/src/com/android/inputmethod/research/MainLogBuffer.java +++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java @@ -119,6 +119,7 @@ public class MainLogBuffer extends FixedLogBuffer { // complete buffer contents in detail. final LinkedList<LogUnit> logUnits = getLogUnits(); final int length = logUnits.size(); + int wordsFound = 0; for (int i = 0; i < length; i++) { final LogUnit logUnit = logUnits.get(i); final String word = logUnit.getWord(); @@ -135,9 +136,18 @@ public class MainLogBuffer extends FixedLogBuffer { + ", isValid: " + (dictionary.isValidWord(word))); } return false; + } else { + wordsFound++; } } } + if (wordsFound < N_GRAM_SIZE) { + // Not enough words. Not unsafe, but reject anyway. + if (DEBUG) { + Log.d(TAG, "not enough words"); + } + return false; + } // All checks have passed; this buffer's content can be safely uploaded. return true; } diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java index a6b1b889f..a2356e6a3 100644 --- a/java/src/com/android/inputmethod/research/ResearchLog.java +++ b/java/src/com/android/inputmethod/research/ResearchLog.java @@ -193,6 +193,9 @@ public class ResearchLog { }); } catch (RejectedExecutionException e) { // TODO: Add code to record loss of data, and report. + if (DEBUG) { + Log.d(TAG, "ResearchLog.publish() rejecting scheduled execution"); + } } } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index b1484e696..b61db272c 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -85,7 +85,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final String TAG = ResearchLogger.class.getSimpleName(); private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Whether all n-grams should be logged. true will disclose private info. - private static final boolean LOG_EVERYTHING = false + private static final boolean IS_LOGGING_EVERYTHING = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Whether the TextView contents are logged at the end of the session. true will disclose // private info. @@ -105,7 +105,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final boolean IS_SHOWING_INDICATOR = true; // Change the default indicator to something very visible. Currently two red vertical bars on // either side of they keyboard. - private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false || LOG_EVERYTHING; + private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false || IS_LOGGING_EVERYTHING; public static final int FEEDBACK_WORD_BUFFER_SIZE = 5; // constants related to specific log points @@ -390,11 +390,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (DEBUG) { Log.d(TAG, "stop called"); } + // Commit mCurrentLogUnit before closing. commitCurrentLogUnit(); if (mMainLogBuffer != null) { publishLogBuffer(mMainLogBuffer, mMainResearchLog, - LOG_EVERYTHING /* isIncludingPrivateData */); + IS_LOGGING_EVERYTHING /* isIncludingPrivateData */); mMainResearchLog.close(null /* callback */); mMainLogBuffer = null; } @@ -676,11 +677,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /** * Buffer a research log event, flagging it as privacy-sensitive. */ - private synchronized void enqueueEvent(LogStatement logStatement, Object... values) { + private synchronized void enqueueEvent(final LogStatement logStatement, + final Object... values) { + enqueueEvent(mCurrentLogUnit, logStatement, values); + } + + private synchronized void enqueueEvent(final LogUnit logUnit, final LogStatement logStatement, + final Object... values) { assert values.length == logStatement.mKeys.length; - if (isAllowedToLog()) { + if (isAllowedToLog() && logUnit != null) { final long time = SystemClock.uptimeMillis(); - mCurrentLogUnit.addLogStatement(logStatement, time, values); + logUnit.addLogStatement(logStatement, time, values); } } @@ -695,12 +702,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } if (!mCurrentLogUnit.isEmpty()) { if (mMainLogBuffer != null) { - mMainLogBuffer.shiftIn(mCurrentLogUnit); - if ((mMainLogBuffer.isSafeToLog() || LOG_EVERYTHING) && mMainResearchLog != null) { + if ((mMainLogBuffer.isSafeToLog() || IS_LOGGING_EVERYTHING) + && mMainResearchLog != null) { publishLogBuffer(mMainLogBuffer, mMainResearchLog, true /* isIncludingPrivateData */); mMainLogBuffer.resetWordCounter(); } + mMainLogBuffer.shiftIn(mCurrentLogUnit); } if (mFeedbackLogBuffer != null) { mFeedbackLogBuffer.shiftIn(mCurrentLogUnit); @@ -709,6 +717,50 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + public void uncommitCurrentLogUnit(final String expectedWord, + final boolean dumpCurrentLogUnit) { + // The user has deleted this word and returned to the previous. Check that the word in the + // logUnit matches the expected word. If so, restore the last log unit committed to be the + // current logUnit. I.e., pull out the last LogUnit from all the LogBuffers, and make + // restore it to mCurrentLogUnit so the new edits are captured with the word. Optionally + // dump the contents of mCurrentLogUnit (useful if they contain deletions of the next word + // that should not be reported to protect user privacy) + // + // Note that we don't use mLastLogUnit here, because it only goes one word back and is only + // needed for reverts, which only happen one back. + if (mMainLogBuffer == null) { + return; + } + final LogUnit oldLogUnit = mMainLogBuffer.peekLastLogUnit(); + + // Check that expected word matches. + if (oldLogUnit != null) { + final String oldLogUnitWord = oldLogUnit.getWord(); + if (!oldLogUnitWord.equals(expectedWord)) { + return; + } + } + + // Uncommit, merging if necessary. + mMainLogBuffer.unshiftIn(); + if (oldLogUnit != null && !dumpCurrentLogUnit) { + oldLogUnit.append(mCurrentLogUnit); + mSavedDownEventTime = Long.MAX_VALUE; + } + if (oldLogUnit == null) { + mCurrentLogUnit = new LogUnit(); + } else { + mCurrentLogUnit = oldLogUnit; + } + if (mFeedbackLogBuffer != null) { + mFeedbackLogBuffer.unshiftIn(); + } + if (DEBUG) { + Log.d(TAG, "uncommitCurrentLogUnit back to " + (mCurrentLogUnit.hasWord() + ? ": '" + mCurrentLogUnit.getWord() + "'" : "")); + } + } + private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_OPENING = new LogStatement("logSegmentStart", false, false, "isIncludingPrivateData"); private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_CLOSING = @@ -751,24 +803,26 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * After this operation completes, mCurrentLogUnit will hold any logStatements that happened * after maxTime. */ - private static final LogStatement LOGSTATEMENT_COMMIT_RECORD_SPLIT_WORDS = - new LogStatement("recordSplitWords", true, false); - /* package for test */ void commitCurrentLogUnitAsWord(final String word, final long maxTime) { + /* package for test */ void commitCurrentLogUnitAsWord(final String word, final long maxTime, + final boolean isBatchMode) { + if (word == null) { + return; + } final Dictionary dictionary = getDictionary(); - if (word != null && word.length() > 0 && hasLetters(word)) { + if (word.length() > 0 && hasLetters(word)) { mCurrentLogUnit.setWord(word); final boolean isDictionaryWord = dictionary != null && dictionary.isValidWord(word); mStatistics.recordWordEntered(isDictionaryWord); } final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime); - enqueueCommitText(word); + enqueueCommitText(word, isBatchMode); commitCurrentLogUnit(); mCurrentLogUnit = newLogUnit; } - public void onWordFinished(final String word) { - commitCurrentLogUnitAsWord(word, mSavedDownEventTime); + public void onWordFinished(final String word, final boolean isBatchMode) { + commitCurrentLogUnitAsWord(word, mSavedDownEventTime, isBatchMode); mSavedDownEventTime = Long.MAX_VALUE; } @@ -863,7 +917,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Integer.toHexString(editorInfo.inputType), Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName, - OUTPUT_FORMAT_VERSION, LOG_EVERYTHING, + OUTPUT_FORMAT_VERSION, IS_LOGGING_EVERYTHING, ProductionFlag.IS_EXPERIMENTAL_DEBUG); } catch (NameNotFoundException e) { e.printStackTrace(); @@ -1060,9 +1114,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: Raw text is added to the TextView. */ - public static void latinIME_onTextInput(final String text) { + public static void latinIME_onTextInput(final String text, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE, isBatchMode); } /** @@ -1074,14 +1128,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new LogStatement("LatinIMEPickSuggestionManually", true, false, "replacedWord", "index", "suggestion", "x", "y"); public static void latinIME_pickSuggestionManually(final String replacedWord, - final int index, final String suggestion) { + final int index, final String suggestion, final boolean isBatchMode) { final String scrubbedWord = scrubDigitsFromString(suggestion); final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PICKSUGGESTIONMANUALLY, scrubDigitsFromString(replacedWord), index, suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); - researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode); researchLogger.mStatistics.recordManualSuggestion(); } @@ -1093,11 +1147,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final LogStatement LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION = new LogStatement("LatinIMEPunctuationSuggestion", false, false, "index", "suggestion", "x", "y"); - public static void latinIME_punctuationSuggestion(final int index, final String suggestion) { + public static void latinIME_punctuationSuggestion(final int index, final String suggestion, + final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION, index, suggestion, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); - researchLogger.commitCurrentLogUnitAsWord(suggestion, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(suggestion, Long.MAX_VALUE, isBatchMode); } /** @@ -1125,11 +1180,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * if a soft space is inserted after a word. */ private static final LogStatement LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE = - new LogStatement("LatinIMESwapSwapperAndSpace", false, false); - public static void latinIME_swapSwapperAndSpace(final String text) { + new LogStatement("LatinIMESwapSwapperAndSpace", false, false, "originalCharacters", + "charactersAfterSwap"); + public static void latinIME_swapSwapperAndSpace(final CharSequence originalCharacters, + final String charactersAfterSwap) { final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); - researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE); + final LogUnit logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit(); + if (logUnit != null) { + researchLogger.enqueueEvent(logUnit, LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE, + originalCharacters, charactersAfterSwap); + } } /** @@ -1137,9 +1197,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: Two spaces have been replaced by period space. */ - public static void latinIME_maybeDoubleSpacePeriod(final String text) { + public static void latinIME_maybeDoubleSpacePeriod(final String text, + final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE, isBatchMode); } /** @@ -1191,12 +1252,18 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new LogStatement("LatinIMERevertCommit", true, false, "committedWord", "originallyTypedWord"); public static void latinIME_revertCommit(final String committedWord, - final String originallyTypedWord) { + final String originallyTypedWord, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, - originallyTypedWord); + final LogUnit logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit(); + if (originallyTypedWord.length() > 0 && hasLetters(originallyTypedWord)) { + if (logUnit != null) { + logUnit.setWord(originallyTypedWord); + } + } + researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit, + LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord); researchLogger.mStatistics.recordRevertCommit(); - researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE, isBatchMode); } /** @@ -1295,9 +1362,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: The IME has reverted ". ", which had previously replaced two typed spaces. */ - public static void richInputConnection_revertDoubleSpacePeriod(final String doubleSpace) { - final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(doubleSpace, Long.MAX_VALUE); + private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_REVERTDOUBLESPACEPERIOD = + new LogStatement("RichInputConnectionRevertDoubleSpacePeriod", false, false); + public static void richInputConnection_revertDoubleSpacePeriod() { + getInstance().enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTION_REVERTDOUBLESPACEPERIOD); } /** @@ -1305,9 +1373,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: The IME has reverted a punctuation swap. */ - public static void richInputConnection_revertSwapPunctuation(final String text) { - final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); + private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_REVERTSWAPPUNCTUATION = + new LogStatement("RichInputConnectionRevertSwapPunctuation", false, false); + public static void richInputConnection_revertSwapPunctuation() { + getInstance().enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTION_REVERTSWAPPUNCTUATION); } /** @@ -1317,16 +1386,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * text input to another word that the user more likely desired to type. */ private static final LogStatement LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION = - new LogStatement("LatinIMECommitCurrentAutoCorrection", true, false, "typedWord", + new LogStatement("LatinIMECommitCurrentAutoCorrection", true, true, "typedWord", "autoCorrection", "separatorString"); public static void latinIme_commitCurrentAutoCorrection(final String typedWord, - final String autoCorrection, final String separatorString) { + final String autoCorrection, final String separatorString, final boolean isBatchMode) { final String scrubbedTypedWord = scrubDigitsFromString(typedWord); final String scrubbedAutoCorrection = scrubDigitsFromString(autoCorrection); final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION, scrubbedTypedWord, scrubbedAutoCorrection, separatorString); - researchLogger.commitCurrentLogUnitAsWord(scrubbedAutoCorrection, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(scrubbedAutoCorrection, Long.MAX_VALUE, + isBatchMode); } private boolean isExpectingCommitText = false; @@ -1340,13 +1410,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // add invocations. private static final LogStatement LOGSTATEMENT_LATINIME_COMMIT_PARTIAL_TEXT = new LogStatement("LatinIMECommitPartialText", true, false, "newCursorPosition"); - public static void latinIME_commitPartialText(final CharSequence committedWord, - final long lastTimestampOfWordData) { + public static void latinIME_commitPartialText(final String committedWord, + final long lastTimestampOfWordData, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - final String scrubbedWord = scrubDigitsFromString(committedWord.toString()); + final String scrubbedWord = scrubDigitsFromString(committedWord); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMIT_PARTIAL_TEXT); - researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData); - researchLogger.mStatistics.recordSplitWords(); + researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData, + isBatchMode); } /** @@ -1357,14 +1427,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT = new LogStatement("RichInputConnectionCommitText", true, false, "newCursorPosition"); - public static void richInputConnection_commitText(final CharSequence committedWord, - final int newCursorPosition) { + public static void richInputConnection_commitText(final String committedWord, + final int newCursorPosition, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - final String scrubbedWord = scrubDigitsFromString(committedWord.toString()); + final String scrubbedWord = scrubDigitsFromString(committedWord); if (!researchLogger.isExpectingCommitText) { researchLogger.enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT, newCursorPosition); - researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode); } researchLogger.isExpectingCommitText = false; } @@ -1373,9 +1443,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * Shared event for logging committed text. */ private static final LogStatement LOGSTATEMENT_COMMITTEXT = - new LogStatement("CommitText", true, false, "committedText"); - private void enqueueCommitText(final CharSequence word) { - enqueueEvent(LOGSTATEMENT_COMMITTEXT, word); + new LogStatement("CommitText", true, false, "committedText", "isBatchMode"); + private void enqueueCommitText(final String word, final boolean isBatchMode) { + enqueueEvent(LOGSTATEMENT_COMMITTEXT, word, isBatchMode); } /** |