aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java3
-rw-r--r--java/src/com/android/inputmethod/compat/LinearLayoutCompatUtils.java55
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java26
-rw-r--r--java/src/com/android/inputmethod/keyboard/MiniKeyboard.java21
-rw-r--r--java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java21
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java13
-rw-r--r--java/src/com/android/inputmethod/latin/MoreSuggestions.java13
-rw-r--r--java/src/com/android/inputmethod/latin/MoreSuggestionsView.java55
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestionsView.java117
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java107
11 files changed, 247 insertions, 190 deletions
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
index b6b86a4a0..a6bb83adf 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
@@ -100,8 +100,7 @@ public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper
public String getLocale() {
if (mObj == null) return mDummyLocale;
final String s = (String)CompatUtils.invoke(mObj, null, METHOD_getLocale);
- if (TextUtils.isEmpty(s)) return DEFAULT_LOCALE;
- return s;
+ return s != null ? s : DEFAULT_LOCALE;
}
public String getMode() {
diff --git a/java/src/com/android/inputmethod/compat/LinearLayoutCompatUtils.java b/java/src/com/android/inputmethod/compat/LinearLayoutCompatUtils.java
deleted file mode 100644
index 674cbe74b..000000000
--- a/java/src/com/android/inputmethod/compat/LinearLayoutCompatUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.compat;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.Log;
-
-import java.lang.reflect.Field;
-
-public class LinearLayoutCompatUtils {
- private static final String TAG = LinearLayoutCompatUtils.class.getSimpleName();
-
- private static final Class<?> CLASS_R_STYLEABLE = CompatUtils.getClass(
- "com.android.internal.R$styleable");
- private static final Field STYLEABLE_VIEW = CompatUtils.getField(
- CLASS_R_STYLEABLE, "View");
- private static final Field STYLEABLE_VIEW_BACKGROUND = CompatUtils.getField(
- CLASS_R_STYLEABLE, "View_background");
- private static final Object VALUE_STYLEABLE_VIEW = CompatUtils.getFieldValue(
- null, null, STYLEABLE_VIEW);
- private static final Integer VALUE_STYLEABLE_VIEW_BACKGROUND =
- (Integer)CompatUtils.getFieldValue(null, null, STYLEABLE_VIEW_BACKGROUND);
-
- public static Drawable getBackgroundDrawable(Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
- if (!(VALUE_STYLEABLE_VIEW instanceof int[]) || VALUE_STYLEABLE_VIEW_BACKGROUND == null) {
- Log.w(TAG, "Can't get View background attribute using reflection");
- return null;
- }
-
- final int[] styleableView = (int[])VALUE_STYLEABLE_VIEW;
- final TypedArray a = context.obtainStyledAttributes(
- attrs, styleableView, defStyleAttr, defStyleRes);
- final Drawable background = a.getDrawable(VALUE_STYLEABLE_VIEW_BACKGROUND);
- a.recycle();
- return background;
- }
-}
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index d9089e199..4ec16bdcf 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -438,8 +438,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mMoreKeysWindow = new PopupWindow(getContext());
mMoreKeysWindow.setBackgroundDrawable(null);
mMoreKeysWindow.setAnimationStyle(R.style.MiniKeyboardAnimation);
- // Allow popup window to be drawn off the screen.
- mMoreKeysWindow.setClippingEnabled(false);
}
mMoreKeysPanel = moreKeysPanel;
mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
@@ -552,7 +550,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mOldKeyIndex = tracker.getKeyIndexOn(lastX, lastY);
tracker.onUpEvent(lastX, lastY, eventTime);
} else if (pointerCount == 1 && oldPointerCount == 1) {
- processMotionEvent(tracker, action, x, y, eventTime, this);
+ tracker.processMotionEvent(action, x, y, eventTime, this);
} else {
Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount
+ " (old " + oldPointerCount + ")");
@@ -575,32 +573,12 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
tracker.onMoveEvent(px, py, eventTime);
}
} else {
- processMotionEvent(getPointerTracker(id), action, x, y, eventTime, this);
+ getPointerTracker(id).processMotionEvent(action, x, y, eventTime, this);
}
return true;
}
- private static void processMotionEvent(PointerTracker tracker, int action, int x, int y,
- long eventTime, PointerTracker.KeyEventHandler handler) {
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- tracker.onDownEvent(x, y, eventTime, handler);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- tracker.onUpEvent(x, y, eventTime);
- break;
- case MotionEvent.ACTION_MOVE:
- tracker.onMoveEvent(x, y, eventTime);
- break;
- case MotionEvent.ACTION_CANCEL:
- tracker.onCancelEvent(x, y, eventTime);
- break;
- }
- }
-
@Override
public void closing() {
super.closing();
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
index da91b62d9..ad8056cc0 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
@@ -123,7 +123,9 @@ public class MiniKeyboard extends Keyboard {
}
mWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth;
- mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
+ // Need to subtract the bottom row's gutter only.
+ mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
+ + mTopPadding + mBottomPadding;
}
// Return key position according to column count (0 is default).
@@ -209,20 +211,9 @@ public class MiniKeyboard extends Keyboard {
super(view.getContext(), new MiniKeyboardParams());
load(parentKeyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
- // HACK: Current mini keyboard design totally relies on the 9-patch
- // padding about horizontal
- // and vertical key spacing. To keep the visual of mini keyboard as
- // is, these hacks are
- // needed to keep having the same horizontal and vertical key
- // spacing.
- mParams.mHorizontalGap = 0;
- mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
- // TODO: When we have correctly padded key background 9-patch
- // drawables for mini keyboard,
- // revert the above hacks and uncomment the following lines.
- // mParams.mHorizontalGap = parentKeyboard.mHorizontalGap;
- // mParams.mVerticalGap = parentKeyboard.mVerticalGap;
-
+ // TODO: Mini keyboard's vertical gap is currently calculated heuristically.
+ // Should revise the algorithm.
+ mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard;
mMoreKeys = parentKey.mMoreKeys;
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
index 29861fe4a..0e6e129bb 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
@@ -79,10 +79,8 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
super(context, attrs, defStyle);
final Resources res = context.getResources();
- // Override default ProximityKeyDetector.
- mKeyDetector = new MoreKeysDetector(res.getDimension(
- R.dimen.mini_keyboard_slide_allowance));
- // Remove gesture detector on mini-keyboard
+ mKeyDetector = new MoreKeysDetector(
+ res.getDimension(R.dimen.mini_keyboard_slide_allowance));
setKeyPreviewPopupEnabled(false, 0);
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 0314867b3..38c419dc6 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
+import android.view.MotionEvent;
import android.widget.TextView;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
@@ -398,6 +399,26 @@ public class PointerTracker {
return onMoveKeyInternal(x, y);
}
+ public void processMotionEvent(int action, int x, int y, long eventTime,
+ KeyEventHandler handler) {
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ onDownEvent(x, y, eventTime, handler);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ onUpEvent(x, y, eventTime);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ onMoveEvent(x, y, eventTime);
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ onCancelEvent(x, y, eventTime);
+ break;
+ }
+ }
+
public void onDownEvent(int x, int y, long eventTime, KeyEventHandler handler) {
if (DEBUG_EVENT)
printTouchEvent("onDownEvent:", x, y, eventTime);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index cea59fe0a..191ae5811 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -157,6 +157,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private Settings.Values mSettingsValues;
+ private View mKeyPreviewBackingView;
private View mSuggestionsContainer;
private int mSuggestionsStripHeight;
private SuggestionsView mSuggestionsView;
@@ -607,6 +608,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
@Override
public void setInputView(View view) {
super.setInputView(view);
+ mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing);
mSuggestionsContainer = view.findViewById(R.id.suggestions_container);
mSuggestionsView = (SuggestionsView) view.findViewById(R.id.suggestions_view);
if (mSuggestionsView != null)
@@ -945,12 +947,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
&& (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
if (isFullscreenMode()) {
// No need to have extra space to show the key preview.
- mSuggestionsContainer.setMinimumHeight(0);
+ mKeyPreviewBackingView.setVisibility(View.GONE);
mSuggestionsContainer.setVisibility(
shouldShowSuggestions ? View.VISIBLE : View.GONE);
} else {
// We must control the visibility of the suggestion strip in order to avoid clipped
// key previews, even when we don't show the suggestion strip.
+ mKeyPreviewBackingView.setVisibility(View.VISIBLE);
mSuggestionsContainer.setVisibility(
shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE);
}
@@ -967,15 +970,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
if (inputView == null || mSuggestionsContainer == null)
return;
- final int containerHeight = mSuggestionsContainer.getHeight();
- int touchY = containerHeight;
+ final int backingHeight = (mKeyPreviewBackingView.getVisibility() == View.GONE) ? 0
+ : mKeyPreviewBackingView.getHeight();
+ final int extraHeight = mSuggestionsContainer.getHeight() + backingHeight;
+ int touchY = extraHeight;
// Need to set touchable region only if input view is being shown
if (mKeyboardSwitcher.isInputViewShown()) {
if (mSuggestionsContainer.getVisibility() == View.VISIBLE) {
touchY -= mSuggestionsStripHeight;
}
final int touchWidth = inputView.getWidth();
- final int touchHeight = inputView.getHeight() + containerHeight
+ final int touchHeight = inputView.getHeight() + extraHeight
// Extend touchable region below the keyboard.
+ EXTENDED_TOUCHABLE_REGION_HEIGHT;
if (DEBUG) {
diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/MoreSuggestions.java
index a9e75b7b3..10d5b5c48 100644
--- a/java/src/com/android/inputmethod/latin/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/MoreSuggestions.java
@@ -50,8 +50,8 @@ public class MoreSuggestions extends Keyboard {
private static final int MAX_COLUMNS_IN_ROW = 3;
private int mNumRows;
- public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int maxHeight,
- KeyboardView view) {
+ public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth,
+ int maxRow, KeyboardView view) {
clearKeys();
final Paint paint = new Paint();
paint.setAntiAlias(true);
@@ -68,7 +68,7 @@ public class MoreSuggestions extends Keyboard {
final int numColumn = pos - rowStartPos + 1;
if (numColumn > MAX_COLUMNS_IN_ROW
|| !fitInWidth(rowStartPos, pos + 1, maxWidth / numColumn)) {
- if ((row + 1) * mDefaultRowHeight > maxHeight) {
+ if ((row + 1) >= maxRow) {
break;
}
mNumColumnsInRow[row] = pos - rowStartPos;
@@ -81,7 +81,7 @@ public class MoreSuggestions extends Keyboard {
}
mNumColumnsInRow[row] = pos - rowStartPos;
mNumRows = row + 1;
- mWidth = mOccupiedWidth = calcurateMaxRowWidth(fromPos, pos);
+ mWidth = mOccupiedWidth = Math.max(minWidth, calcurateMaxRowWidth(fromPos, pos));
mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
return pos - fromPos;
}
@@ -163,13 +163,14 @@ public class MoreSuggestions extends Keyboard {
}
public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth,
- int maxHeight) {
+ int minWidth, int maxRow) {
final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard();
final int xmlId = R.xml.kbd_suggestions_pane_template;
load(keyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
- final int count = mParams.layout(suggestions, fromPos, maxWidth, maxHeight, mPaneView);
+ final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,
+ mPaneView);
mFromPos = fromPos;
mToPos = fromPos + count;
mSuggestions = suggestions;
diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java
index 9fd90241b..f595510a3 100644
--- a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.PopupWindow;
@@ -29,7 +30,9 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.MoreKeysDetector;
import com.android.inputmethod.keyboard.MoreKeysPanel;
+import com.android.inputmethod.keyboard.PointerTracker;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
+import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
@@ -40,7 +43,8 @@ import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
private final int[] mCoordinates = new int[2];
- private final KeyDetector mKeyDetector;
+ private final KeyDetector mModalPanelKeyDetector;
+ private final KeyDetector mSlidingPanelKeyDetector;
private Controller mController;
private KeyboardActionListener mListener;
@@ -73,17 +77,16 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
};
public MoreSuggestionsView(Context context, AttributeSet attrs) {
- this(context, attrs, R.attr.suggestionsPaneViewStyle);
+ this(context, attrs, R.attr.moreSuggestionsViewStyle);
}
public MoreSuggestionsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final Resources res = context.getResources();
- // Override default ProximityKeyDetector.
- mKeyDetector = new MoreKeysDetector(res.getDimension(
- R.dimen.more_suggestions_slide_allowance));
- // Remove gesture detector on suggestions pane
+ mModalPanelKeyDetector = new KeyDetector(/* keyHysteresisDistance */ 0);
+ mSlidingPanelKeyDetector = new MoreKeysDetector(
+ res.getDimension(R.dimen.more_suggestions_slide_allowance));
setKeyPreviewPopupEnabled(false, 0);
}
@@ -102,13 +105,14 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
@Override
public void setKeyboard(Keyboard keyboard) {
super.setKeyboard(keyboard);
- mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
+ mModalPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop());
+ mSlidingPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
-getPaddingTop() + mVerticalCorrection);
}
@Override
public KeyDetector getKeyDetector() {
- return mKeyDetector;
+ return mSlidingPanelKeyDetector;
}
@Override
@@ -187,4 +191,39 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
public int translateY(int y) {
return y - mOriginY;
}
+
+ private final KeyEventHandler mModalPanelKeyEventHandler = new KeyEventHandler() {
+ @Override
+ public KeyDetector getKeyDetector() {
+ return mModalPanelKeyDetector;
+ }
+
+ @Override
+ public KeyboardActionListener getKeyboardActionListener() {
+ return mSuggestionsPaneListener;
+ }
+
+ @Override
+ public DrawingProxy getDrawingProxy() {
+ return MoreSuggestionsView.this;
+ }
+
+ @Override
+ public TimerProxy getTimerProxy() {
+ return EMPTY_TIMER_PROXY;
+ }
+ };
+
+ @Override
+ public boolean onTouchEvent(MotionEvent me) {
+ final int action = me.getAction();
+ final long eventTime = me.getEventTime();
+ final int index = me.getActionIndex();
+ final int id = me.getPointerId(index);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
+ tracker.processMotionEvent(action, x, y, eventTime, mModalPanelKeyEventHandler);
+ return true;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java
index 10cd73dd3..22aa5e259 100644
--- a/java/src/com/android/inputmethod/latin/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java
@@ -35,7 +35,6 @@ import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.text.style.UnderlineSpan;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -45,10 +44,10 @@ import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.inputmethod.compat.FrameLayoutCompatUtils;
-import com.android.inputmethod.compat.LinearLayoutCompatUtils;
import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.MoreKeysPanel;
@@ -58,7 +57,8 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import java.util.ArrayList;
import java.util.List;
-public class SuggestionsView extends LinearLayout implements OnClickListener, OnLongClickListener {
+public class SuggestionsView extends RelativeLayout implements OnClickListener,
+ OnLongClickListener {
public interface Listener {
public boolean addWordToDictionary(String word);
public void pickSuggestionManually(int index, CharSequence word);
@@ -69,7 +69,6 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
private static final boolean DBG = LatinImeLogger.sDBG;
- private final ViewGroup mSuggestionsPlacer;
private final ViewGroup mSuggestionsStrip;
private KeyboardView mKeyboardView;
@@ -146,12 +145,16 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
private static class SuggestionsViewParams {
private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3;
private static final int DEFAULT_CENTER_SUGGESTION_PERCENTILE = 40;
+ private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2;
private static final int PUNCTUATIONS_IN_STRIP = 6;
public final int mPadding;
public final int mDividerWidth;
public final int mSuggestionsStripHeight;
public final int mSuggestionsCountInStrip;
+ public final int mMaxMoreSuggestionsRow;
+ public final float mMinMoreSuggestionsWidth;
+ public final int mMoreSuggestionsBottomGap;
private final List<TextView> mWords;
private final List<View> mDividers;
@@ -211,10 +214,17 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
mCenterSuggestionWeight = a.getInt(
R.styleable.SuggestionsView_centerSuggestionPercentile,
DEFAULT_CENTER_SUGGESTION_PERCENTILE) / 100.0f;
+ mMaxMoreSuggestionsRow = a.getInt(
+ R.styleable.SuggestionsView_maxMoreSuggestionsRow,
+ DEFAULT_MAX_MORE_SUGGESTIONS_ROW);
+ mMinMoreSuggestionsWidth = getRatio(a,
+ R.styleable.SuggestionsView_minMoreSuggestionsWidth);
a.recycle();
mCenterSuggestionIndex = mSuggestionsCountInStrip / 2;
mMoreSuggestionsHint = res.getDrawable(R.drawable.more_suggestions_hint);
+ mMoreSuggestionsBottomGap = res.getDimensionPixelOffset(
+ R.dimen.more_suggestions_bottom_gap);
mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
@@ -225,6 +235,11 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
}
+ // Read fraction value in TypedArray as float.
+ private static float getRatio(TypedArray a, int index) {
+ return a.getFraction(index, 1000, 1000, 1) / 1000.0f;
+ }
+
private CharSequence getStyledSuggestionWord(SuggestedWords suggestions, int pos) {
final CharSequence word = suggestions.getWord(pos);
final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions);
@@ -451,18 +466,7 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
}
public SuggestionsView(Context context, AttributeSet attrs, int defStyle) {
- // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument
- // constructor.
- // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon
- // backward compatibility with the version 10 or earlier of the API.
- super(context, attrs);
- if (defStyle != R.attr.suggestionsViewStyle) {
- throw new IllegalArgumentException(
- "can't accept defStyle other than R.attr.suggestionsViewStyle: defStyle="
- + defStyle);
- }
- setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable(
- context, attrs, defStyle, R.style.SuggestionsViewStyle));
+ super(context, attrs, defStyle);
final LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.suggestions_strip, this);
@@ -474,7 +478,6 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
mPreviewPopup.setContentView(mPreviewText);
mPreviewPopup.setBackgroundDrawable(null);
- mSuggestionsPlacer = (ViewGroup)findViewById(R.id.suggestions_placer);
mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
@@ -500,6 +503,9 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
mMoreSuggestionsWindow.setWindowLayoutMode(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mMoreSuggestionsWindow.setBackgroundDrawable(null);
+ final Resources res = context.getResources();
+ mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(
+ R.dimen.more_suggestions_modal_tolerance);
}
/**
@@ -527,7 +533,7 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
if (mSuggestions.size() == 0)
return;
- mParams.layout(mSuggestions, mSuggestionsStrip, mSuggestionsPlacer, getWidth());
+ mParams.layout(mSuggestions, mSuggestionsStrip, this, getWidth());
}
private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
@@ -648,9 +654,9 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
public void clear() {
mShowingAutoCorrectionInverted = false;
- mSuggestionsPlacer.removeAllViews();
- mSuggestionsPlacer.addView(mSuggestionsStrip);
mSuggestionsStrip.removeAllViews();
+ removeAllViews();
+ addView(mSuggestionsStrip);
dismissMoreSuggestions();
}
@@ -730,27 +736,23 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
final View container = mMoreSuggestionsContainer;
final int maxWidth = stripWidth - container.getPaddingLeft()
- container.getPaddingRight();
- final DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
- // TODO: Revise how we determine the height
- final int maxHeight = dm.heightPixels - mKeyboardView.getHeight() - getHeight() * 3;
final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
- builder.layout(mSuggestions, params.mSuggestionsCountInStrip, maxWidth, maxHeight);
+ builder.layout(mSuggestions, params.mSuggestionsCountInStrip, maxWidth,
+ (int)(maxWidth * params.mMinMoreSuggestionsWidth),
+ params.mMaxMoreSuggestionsRow);
mMoreSuggestionsView.setKeyboard(builder.build());
container.measure(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
final int pointX = stripWidth / 2;
- final int pointY = 0;
+ final int pointY = -params.mMoreSuggestionsBottomGap;
moreKeysPanel.showMoreKeysPanel(
this, mMoreSuggestionsController, pointX, pointY,
mMoreSuggestionsWindow, mMoreSuggestionsListener);
- // TODO: Should figure out how to select the pointer tracker correctly.
- final PointerTracker tracker = PointerTracker.getPointerTracker(0, moreKeysPanel);
- final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
- final int translatedY = moreKeysPanel.translateY(tracker.getLastY());
- tracker.onShowMoreKeysPanel(
- translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel);
+ mCheckingIfModalOrSlidingMode = true;
+ mOriginX = mLastX;
+ mOriginY = mLastY;
view.setPressed(false);
mKeyboardView.dimEntireKeyboard(true);
return true;
@@ -758,34 +760,51 @@ public class SuggestionsView extends LinearLayout implements OnClickListener, On
return false;
}
+ // Working variables for onLongClick and dispatchTouchEvent.
+ private boolean mCheckingIfModalOrSlidingMode;
+ private int mLastX;
+ private int mLastY;
+ private int mOriginX;
+ private int mOriginY;
+ private final int mMoreSuggestionsModalTolerance;
+
@Override
public boolean dispatchTouchEvent(MotionEvent me) {
if (!mMoreSuggestionsWindow.isShowing()) {
+ mLastX = (int)me.getX();
+ mLastY = (int)me.getY();
return super.dispatchTouchEvent(me);
}
+
+ final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
final int action = me.getAction();
final long eventTime = me.getEventTime();
final int index = me.getActionIndex();
final int id = me.getPointerId(index);
- final PointerTracker tracker = PointerTracker.getPointerTracker(id, mMoreSuggestionsView);
- final int x = mMoreSuggestionsView.translateX((int)me.getX(index));
- final int y = mMoreSuggestionsView.translateY((int)me.getY(index));
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- tracker.onDownEvent(x, y, eventTime, mMoreSuggestionsView);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- tracker.onUpEvent(x, y, eventTime);
- break;
- case MotionEvent.ACTION_MOVE:
- tracker.onMoveEvent(x, y, eventTime);
- break;
- case MotionEvent.ACTION_CANCEL:
- tracker.onCancelEvent(x, y, eventTime);
- break;
+ final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel);
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
+ final int translatedX = moreKeysPanel.translateX(x);
+ final int translatedY = moreKeysPanel.translateY(y);
+
+ if (mCheckingIfModalOrSlidingMode) {
+ final int deltaX = Math.abs(x - mOriginX);
+ final int deltaY = Math.abs(y - mOriginY);
+ if (deltaX >= mMoreSuggestionsModalTolerance
+ || deltaY >= mMoreSuggestionsModalTolerance) {
+ // Decided to be in the sliding input mode
+ mCheckingIfModalOrSlidingMode = false;
+ tracker.onShowMoreKeysPanel(
+ translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel);
+ } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
+ // Decided to be in the modal input mode
+ mCheckingIfModalOrSlidingMode = false;
+ }
+ return true;
}
+
+ // Process sliding motion events
+ tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel);
return true;
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index a6a5b6dd6..85c142f1e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -34,6 +34,7 @@ import com.android.inputmethod.latin.Dictionary.WordCallback;
import com.android.inputmethod.latin.DictionaryCollection;
import com.android.inputmethod.latin.DictionaryFactory;
import com.android.inputmethod.latin.LocaleUtils;
+import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary;
import com.android.inputmethod.latin.UserDictionary;
import com.android.inputmethod.latin.Utils;
@@ -62,18 +63,38 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
private Map<String, Dictionary> mUserDictionaries =
Collections.synchronizedMap(new TreeMap<String, Dictionary>());
+ private double mTypoThreshold;
+
+ @Override public void onCreate() {
+ super.onCreate();
+ mTypoThreshold = Double.parseDouble(getString(R.string.spellchecker_typo_threshold_value));
+ }
+
@Override
public Session createSession() {
- return new AndroidSpellCheckerSession();
+ return new AndroidSpellCheckerSession(this);
}
private static class SuggestionsGatherer implements WordCallback {
+ public static class Result {
+ public final String[] mSuggestions;
+ public final boolean mLooksLikeTypo;
+ public Result(final String[] gatheredSuggestions, final boolean looksLikeTypo) {
+ mSuggestions = gatheredSuggestions;
+ mLooksLikeTypo = looksLikeTypo;
+ }
+ }
+
private final int DEFAULT_SUGGESTION_LENGTH = 16;
private final ArrayList<CharSequence> mSuggestions;
private final int[] mScores;
private final int mMaxLength;
private int mLength = 0;
- private boolean mSeenSuggestions = false;
+
+ // The two following attributes are only ever filled if the requested max length
+ // is 0 (or less, which is treated the same).
+ private String mBestSuggestion = null;
+ private int mBestScore = Integer.MIN_VALUE; // As small as possible
SuggestionsGatherer(final int maxLength) {
mMaxLength = maxLength;
@@ -89,14 +110,26 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
// if it doesn't. See documentation for binarySearch.
final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1;
- mSeenSuggestions = true;
if (mLength < mMaxLength) {
final int copyLen = mLength - insertIndex;
++mLength;
System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen);
mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength));
} else {
- if (insertIndex == 0) return true;
+ if (insertIndex == 0) {
+ // If the maxLength is 0 (should never be less, but if it is, it's treated as 0)
+ // then we need to keep track of the best suggestion in mBestScore and
+ // mBestSuggestion. This is so that we know whether the best suggestion makes
+ // the score cutoff, since we need to know that to return a meaningful
+ // looksLikeTypo.
+ if (0 >= mMaxLength) {
+ if (score > mBestScore) {
+ mBestScore = score;
+ mBestSuggestion = new String(word, wordOffset, wordLength);
+ }
+ }
+ return true;
+ }
System.arraycopy(mScores, 1, mScores, 0, insertIndex);
mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength));
mSuggestions.remove(0);
@@ -106,20 +139,41 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
return true;
}
- public String[] getGatheredSuggestions() {
- if (!mSeenSuggestions) return null;
- if (0 == mLength) return EMPTY_STRING_ARRAY;
-
- if (DBG) {
- if (mLength != mSuggestions.size()) {
- Log.e(TAG, "Suggestion size is not the same as stored mLength");
+ public Result getResults(final CharSequence originalText, final double threshold) {
+ final String[] gatheredSuggestions;
+ final boolean looksLikeTypo;
+ if (0 == mLength) {
+ // Either we found no suggestions, or we found some BUT the max length was 0.
+ // If we found some mBestSuggestion will not be null. If it is null, then
+ // we found none, regardless of the max length.
+ if (null == mBestSuggestion) {
+ gatheredSuggestions = null;
+ looksLikeTypo = false;
+ } else {
+ gatheredSuggestions = EMPTY_STRING_ARRAY;
+ final double normalizedScore =
+ Utils.calcNormalizedScore(originalText, mBestSuggestion, mBestScore);
+ looksLikeTypo = (normalizedScore > threshold);
+ }
+ } else {
+ if (DBG) {
+ if (mLength != mSuggestions.size()) {
+ Log.e(TAG, "Suggestion size is not the same as stored mLength");
+ }
}
+ Collections.reverse(mSuggestions);
+ Utils.removeDupes(mSuggestions);
+ // This returns a String[], while toArray() returns an Object[] which cannot be cast
+ // into a String[].
+ gatheredSuggestions = mSuggestions.toArray(EMPTY_STRING_ARRAY);
+
+ final int bestScore = mScores[0];
+ final CharSequence bestSuggestion = mSuggestions.get(0);
+ final double normalizedScore =
+ Utils.calcNormalizedScore(originalText, bestSuggestion, bestScore);
+ looksLikeTypo = (normalizedScore > threshold);
}
- Collections.reverse(mSuggestions);
- Utils.removeDupes(mSuggestions);
- // This returns a String[], while toArray() returns an Object[] which cannot be cast
- // into a String[].
- return mSuggestions.toArray(EMPTY_STRING_ARRAY);
+ return new Result(gatheredSuggestions, looksLikeTypo);
}
}
@@ -164,16 +218,22 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
return new DictAndProximity(dictionaryCollection, proximityInfo);
}
- private class AndroidSpellCheckerSession extends Session {
+ private static class AndroidSpellCheckerSession extends Session {
// Immutable, but need the locale which is not available in the constructor yet
- DictionaryPool mDictionaryPool;
+ private DictionaryPool mDictionaryPool;
// Likewise
- Locale mLocale;
+ private Locale mLocale;
+
+ private final AndroidSpellCheckerService mService;
+
+ AndroidSpellCheckerSession(final AndroidSpellCheckerService service) {
+ mService = service;
+ }
@Override
public void onCreate() {
final String localeString = getLocale();
- mDictionaryPool = getDictionaryPool(localeString);
+ mDictionaryPool = mService.getDictionaryPool(localeString);
mLocale = LocaleUtils.constructLocaleFromString(localeString);
}
@@ -242,13 +302,14 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
return EMPTY_SUGGESTIONS_INFO;
}
- final String[] suggestions = suggestionsGatherer.getGatheredSuggestions();
+ final SuggestionsGatherer.Result result =
+ suggestionsGatherer.getResults(text, mService.mTypoThreshold);
final int flags =
(isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY : 0)
- | (null != suggestions
+ | (result.mLooksLikeTypo
? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0);
- return new SuggestionsInfo(flags, suggestions);
+ return new SuggestionsInfo(flags, result.mSuggestions);
}
}
}