diff options
Diffstat (limited to 'java/src/com/android/inputmethod')
17 files changed, 853 insertions, 272 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index c3db1b318..b919bcfc4 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -30,7 +30,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.KeyboardParams; -import com.android.inputmethod.keyboard.internal.PopupCharactersParser; +import com.android.inputmethod.keyboard.internal.MoreKeySpecParser; import com.android.inputmethod.keyboard.internal.Row; import com.android.inputmethod.latin.R; @@ -90,10 +90,10 @@ public class Key { public final int mY; /** Text to output when pressed. This can be multiple characters, like ".com" */ public final CharSequence mOutputText; - /** Popup characters */ - public final CharSequence[] mPopupCharacters; - /** Popup keyboard maximum column number */ - public final int mMaxPopupColumn; + /** More keys */ + public final CharSequence[] mMoreKeys; + /** More keys maximum column number */ + public final int mMaxMoreKeysColumn; /** * Flags that specify the anchoring to edges of the keyboard for detecting touch events @@ -192,21 +192,30 @@ public class Key { } } + private static int getCode(Resources res, KeyboardParams params, String moreKeySpec) { + return getRtlParenthesisCode( + MoreKeySpecParser.getCode(res, moreKeySpec), params.mIsRtlKeyboard); + } + + private static Drawable getIcon(KeyboardParams params, String moreKeySpec) { + return params.mIconsSet.getIcon(MoreKeySpecParser.getIconId(moreKeySpec)); + } + /** - * This constructor is being used only for key in popup mini keyboard. + * This constructor is being used only for key in more keys keyboard. */ - public Key(Resources res, KeyboardParams params, String popupSpec, + public Key(Resources res, KeyboardParams params, String moreKeySpec, int x, int y, int width, int height, int edgeFlags) { - this(params, getRtlParenthesisCode(PopupCharactersParser.getCode(res, popupSpec), - params.mIsRtlKeyboard), - popupSpec, null, x, y, width, height, edgeFlags); + this(params, MoreKeySpecParser.getLabel(moreKeySpec), null, getIcon(params, moreKeySpec), + getCode(res, params, moreKeySpec), MoreKeySpecParser.getOutputText(moreKeySpec), + x, y, width, height, edgeFlags); } /** * This constructor is being used only for key in popup suggestions pane. */ - public Key(KeyboardParams params, int code, String popupSpec, String hintLabel, - int x, int y, int width, int height, int edgeFlags) { + public Key(KeyboardParams params, CharSequence label, CharSequence hintLabel, Drawable icon, + int code, CharSequence outputText, int x, int y, int width, int height, int edgeFlags) { mHeight = height - params.mVerticalGap; mHorizontalGap = params.mHorizontalGap; mVerticalGap = params.mVerticalGap; @@ -218,12 +227,12 @@ public class Key { mFunctional = false; mSticky = false; mRepeatable = false; - mPopupCharacters = null; - mMaxPopupColumn = 0; - mLabel = PopupCharactersParser.getLabel(popupSpec); - mOutputText = PopupCharactersParser.getOutputText(popupSpec); + mMoreKeys = null; + mMaxMoreKeysColumn = 0; + mLabel = label; + mOutputText = outputText; mCode = code; - mIcon = params.mIconsSet.getIcon(PopupCharactersParser.getIconId(popupSpec)); + mIcon = icon; // Horizontal gap is divided equally to both sides of the key. mX = x + mHorizontalGap / 2; mY = y; @@ -303,20 +312,20 @@ public class Key { mY = y; mWidth = keyWidth - mHorizontalGap; - final CharSequence[] popupCharacters = style.getTextArray( - keyAttr, R.styleable.Keyboard_Key_popupCharacters); - // In Arabic symbol layouts, we'd like to keep digits in popup characters regardless of - // config_digit_popup_characters_enabled. + final CharSequence[] moreKeys = style.getTextArray( + keyAttr, R.styleable.Keyboard_Key_moreKeys); + // In Arabic symbol layouts, we'd like to keep digits in more keys regardless of + // config_digit_more_keys_enabled. if (params.mId.isAlphabetKeyboard() && !res.getBoolean( - R.bool.config_digit_popup_characters_enabled)) { - mPopupCharacters = PopupCharactersParser.filterOut( - res, popupCharacters, PopupCharactersParser.DIGIT_FILTER); + R.bool.config_digit_more_keys_enabled)) { + mMoreKeys = MoreKeySpecParser.filterOut( + res, moreKeys, MoreKeySpecParser.DIGIT_FILTER); } else { - mPopupCharacters = popupCharacters; + mMoreKeys = moreKeys; } - mMaxPopupColumn = style.getInt(keyboardAttr, - R.styleable.Keyboard_Key_maxPopupKeyboardColumn, - params.mMaxPopupColumn); + mMaxMoreKeysColumn = style.getInt(keyboardAttr, + R.styleable.Keyboard_Key_maxMoreKeysColumn, + params.mMaxMiniKeyboardColumn); mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false); mFunctional = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isFunctional, false); diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index f8e08b06a..3a8a1d4b8 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -101,11 +101,11 @@ public class Keyboard { public final int mMostCommonKeyWidth; - /** Popup keyboard template */ - public final int mPopupKeyboardResId; + /** More keys keyboard template */ + public final int mMoreKeysTemplate; - /** Maximum column for popup keyboard */ - public final int mMaxPopupColumn; + /** Maximum column for mini keyboard */ + public final int mMaxMiniKeyboardColumn; /** True if Right-To-Left keyboard */ public final boolean mIsRtlKeyboard; @@ -130,8 +130,8 @@ public class Keyboard { mWidth = params.mWidth; mMostCommonKeyWidth = params.mMostCommonKeyWidth; mIsRtlKeyboard = params.mIsRtlKeyboard; - mPopupKeyboardResId = params.mPopupKeyboardResId; - mMaxPopupColumn = params.mMaxPopupColumn; + mMoreKeysTemplate = params.mMoreKeysTemplate; + mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn; mDefaultRowHeight = params.mDefaultRowHeight; mVerticalGap = params.mVerticalGap; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 5f824537e..ceadc919c 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -77,7 +77,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // Miscellaneous constants private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable }; - // XML attribute + // XML attributes + protected final float mVerticalCorrection; + protected final int mMoreKeysLayout; private final float mBackgroundDimAmount; // HORIZONTAL ELLIPSIS "...", character for popup hint. @@ -122,9 +124,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { new HashMap<Integer, Float>(); private static final String KEY_LABEL_REFERENCE_CHAR = "M"; - private static final int MEASURESPEC_UNSPECIFIED = MeasureSpec.makeMeasureSpec( - 0, MeasureSpec.UNSPECIFIED); - private final DrawingHandler mDrawingHandler = new DrawingHandler(this); public static class DrawingHandler extends StaticInnerHandlerWrapper<KeyboardView> { @@ -342,6 +341,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (mKeyPreviewLayoutId == 0) { mShowKeyPreviewPopup = false; } + mVerticalCorrection = a.getDimensionPixelOffset( + R.styleable.KeyboardView_verticalCorrection, 0); + mMoreKeysLayout = a.getResourceId(R.styleable.KeyboardView_moreKeysLayout, 0); mBackgroundDimAmount = a.getFloat(R.styleable.KeyboardView_backgroundDimAmount, 0.5f); a.recycle(); @@ -677,7 +679,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } // Draw popup hint "..." at the bottom right corner of the key. - if ((key.hasPopupHint() && key.mPopupCharacters != null && key.mPopupCharacters.length > 0) + if ((key.hasPopupHint() && key.mMoreKeys != null && key.mMoreKeys.length > 0) || key.needsSpecialPopupHint()) { paint.setTextSize(params.mKeyHintLetterSize); paint.setColor(params.mKeyHintLabelColor); @@ -859,7 +861,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } previewText.setBackgroundDrawable(params.mPreviewBackground); - previewText.measure(MEASURESPEC_UNSPECIFIED, MEASURESPEC_UNSPECIFIED); + previewText.measure( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); final int previewWidth = Math.max(previewText.getMeasuredWidth(), keyDrawWidth + previewText.getPaddingLeft() + previewText.getPaddingRight()); final int previewHeight = params.mPreviewHeight; @@ -877,7 +880,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // Set the preview background state previewText.getBackground().setState( - key.mPopupCharacters != null ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); + key.mMoreKeys != null ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); previewText.setTextColor(params.mPreviewTextColor); FrameLayoutCompatUtils.placeViewAt( previewText, previewX, previewY, previewWidth, previewHeight); @@ -925,7 +928,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } @Override - public boolean dismissPopupPanel() { + public boolean dismissMoreKeysPanel() { return false; } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 69cbcb154..777bae3b0 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -19,7 +19,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.content.res.TypedArray; import android.graphics.Canvas; import android.os.Message; import android.os.SystemClock; @@ -30,6 +29,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.widget.PopupWindow; @@ -63,16 +63,12 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Timing constants private final int mKeyRepeatInterval; - // XML attribute - private final float mVerticalCorrection; - private final int mPopupLayout; - // Mini keyboard - private PopupWindow mPopupWindow; - private PopupPanel mPopupPanel; - private int mPopupPanelPointerTrackerId; - private final WeakHashMap<Key, PopupPanel> mPopupPanelCache = - new WeakHashMap<Key, PopupPanel>(); + private PopupWindow mMoreKeysWindow; + private MoreKeysPanel mMoreKeysPanel; + private int mMoreKeysPanelPointerTrackerId; + private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache = + new WeakHashMap<Key, MoreKeysPanel>(); /** Listener for {@link KeyboardActionListener}. */ private KeyboardActionListener mKeyboardActionListener; @@ -218,13 +214,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this); - final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - mVerticalCorrection = a.getDimensionPixelOffset( - R.styleable.KeyboardView_verticalCorrection, 0); - mPopupLayout = a.getResourceId(R.styleable.KeyboardView_popupLayout, 0); - a.recycle(); - final Resources res = getResources(); mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean( R.bool.config_show_mini_keyboard_at_touched_point); @@ -308,7 +297,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mKeyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); PointerTracker.setKeyDetector(mKeyDetector); mTouchScreenRegulator.setKeyboard(keyboard); - mPopupPanelCache.clear(); + mMoreKeysPanelCache.clear(); } /** @@ -344,12 +333,12 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private boolean openMiniKeyboardIfRequired(int keyIndex, PointerTracker tracker) { // Check if we have a popup layout specified first. - if (mPopupLayout == 0) { + if (mMoreKeysLayout == 0) { return false; } // Check if we are already displaying popup panel. - if (mPopupPanel != null) + if (mMoreKeysPanel != null) return false; final Key parentKey = tracker.getKey(keyIndex); if (parentKey == null) @@ -364,31 +353,29 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0); } - // This default implementation returns a popup mini keyboard panel. - protected PopupPanel onCreatePopupPanel(Key parentKey) { - if (parentKey.mPopupCharacters == null) + // This default implementation returns a more keys panel. + protected MoreKeysPanel onCreateMoreKeysPanel(Key parentKey) { + if (parentKey.mMoreKeys == null) return null; - final View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null); + final View container = LayoutInflater.from(getContext()).inflate(mMoreKeysLayout, null); if (container == null) throw new NullPointerException(); - final PopupMiniKeyboardView miniKeyboardView = - (PopupMiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); + final MiniKeyboardView miniKeyboardView = + (MiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); final Keyboard parentKeyboard = getKeyboard(); final Keyboard miniKeyboard = new MiniKeyboard.Builder( - this, parentKeyboard.mPopupKeyboardResId, parentKey, parentKeyboard).build(); + this, parentKeyboard.mMoreKeysTemplate, parentKey, parentKeyboard).build(); miniKeyboardView.setKeyboard(miniKeyboard); - - container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); return miniKeyboardView; } @Override protected boolean needsToDimKeyboard() { - return mPopupPanel != null; + return mMoreKeysPanel != null; } public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboard oldKeyboard) { @@ -430,10 +417,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke tracker.onLongPressed(); return true; } else { - return openPopupPanel(parentKey, tracker); + return openMoreKeysPanel(parentKey, tracker); } } else { - return openPopupPanel(parentKey, tracker); + return openMoreKeysPanel(parentKey, tracker); } } @@ -444,34 +431,35 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke return true; } - private boolean openPopupPanel(Key parentKey, PointerTracker tracker) { - PopupPanel popupPanel = mPopupPanelCache.get(parentKey); - if (popupPanel == null) { - popupPanel = onCreatePopupPanel(parentKey); - if (popupPanel == null) + private boolean openMoreKeysPanel(Key parentKey, PointerTracker tracker) { + MoreKeysPanel moreKeysPanel = mMoreKeysPanelCache.get(parentKey); + if (moreKeysPanel == null) { + moreKeysPanel = onCreateMoreKeysPanel(parentKey); + if (moreKeysPanel == null) return false; - mPopupPanelCache.put(parentKey, popupPanel); + mMoreKeysPanelCache.put(parentKey, moreKeysPanel); } - if (mPopupWindow == null) { - mPopupWindow = new PopupWindow(getContext()); - mPopupWindow.setBackgroundDrawable(null); - mPopupWindow.setAnimationStyle(R.style.PopupMiniKeyboardAnimation); + if (mMoreKeysWindow == null) { + mMoreKeysWindow = new PopupWindow(getContext()); + mMoreKeysWindow.setBackgroundDrawable(null); + mMoreKeysWindow.setAnimationStyle(R.style.MiniKeyboardAnimation); // Allow popup window to be drawn off the screen. - mPopupWindow.setClippingEnabled(false); + mMoreKeysWindow.setClippingEnabled(false); } - mPopupPanel = popupPanel; - mPopupPanelPointerTrackerId = tracker.mPointerId; + mMoreKeysPanel = moreKeysPanel; + mMoreKeysPanelPointerTrackerId = tracker.mPointerId; final Keyboard keyboard = getKeyboard(); - popupPanel.setShifted(keyboard.isShiftedOrShiftLocked()); + moreKeysPanel.setShifted(keyboard.isShiftedOrShiftLocked()); final int pointX = (mConfigShowMiniKeyboardAtTouchedPoint) ? tracker.getLastX() : parentKey.mX + parentKey.mWidth / 2; final int pointY = parentKey.mY - keyboard.mVerticalGap; - popupPanel.showPopupPanel( - this, this, pointX, pointY, mPopupWindow, getKeyboardActionListener()); - final int translatedX = popupPanel.translateX(tracker.getLastX()); - final int translatedY = popupPanel.translateY(tracker.getLastY()); - tracker.onShowPopupPanel(translatedX, translatedY, SystemClock.uptimeMillis(), popupPanel); + moreKeysPanel.showMoreKeysPanel( + this, this, pointX, pointY, mMoreKeysWindow, getKeyboardActionListener()); + final int translatedX = moreKeysPanel.translateX(tracker.getLastX()); + final int translatedY = moreKeysPanel.translateY(tracker.getLastY()); + tracker.onShowMoreKeysPanel( + translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel); invalidateAllKeys(); return true; @@ -482,7 +470,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } public boolean isInSlidingKeyInput() { - if (mPopupPanel != null) { + if (mMoreKeysPanel != null) { return true; } else { return PointerTracker.isAnyInSlidingKeyInput(); @@ -517,7 +505,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } // Gesture detector must be enabled only when mini-keyboard is not on the screen. - if (mPopupPanel == null && mGestureDetector != null + if (mMoreKeysPanel == null && mGestureDetector != null && mGestureDetector.onTouchEvent(me)) { PointerTracker.dismissAllKeyPreviews(); mKeyTimerHandler.cancelKeyTimers(); @@ -528,9 +516,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final int index = me.getActionIndex(); final int id = me.getPointerId(index); final int x, y; - if (mPopupPanel != null && id == mPopupPanelPointerTrackerId) { - x = mPopupPanel.translateX((int)me.getX(index)); - y = mPopupPanel.translateY((int)me.getY(index)); + if (mMoreKeysPanel != null && id == mMoreKeysPanelPointerTrackerId) { + x = mMoreKeysPanel.translateX((int)me.getX(index)); + y = mMoreKeysPanel.translateY((int)me.getY(index)); } else { x = (int)me.getX(index); y = (int)me.getY(index); @@ -582,9 +570,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke for (int i = 0; i < pointerCount; i++) { final PointerTracker tracker = getPointerTracker(me.getPointerId(i)); final int px, py; - if (mPopupPanel != null && tracker.mPointerId == mPopupPanelPointerTrackerId) { - px = mPopupPanel.translateX((int)me.getX(i)); - py = mPopupPanel.translateY((int)me.getY(i)); + if (mMoreKeysPanel != null + && tracker.mPointerId == mMoreKeysPanelPointerTrackerId) { + px = mMoreKeysPanel.translateX((int)me.getX(i)); + py = mMoreKeysPanel.translateY((int)me.getY(i)); } else { px = (int)me.getX(i); py = (int)me.getY(i); @@ -621,16 +610,16 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke @Override public void closing() { super.closing(); - dismissPopupPanel(); - mPopupPanelCache.clear(); + dismissMoreKeysPanel(); + mMoreKeysPanelCache.clear(); } @Override - public boolean dismissPopupPanel() { - if (mPopupWindow != null && mPopupWindow.isShowing()) { - mPopupWindow.dismiss(); - mPopupPanel = null; - mPopupPanelPointerTrackerId = -1; + public boolean dismissMoreKeysPanel() { + if (mMoreKeysWindow != null && mMoreKeysWindow.isShowing()) { + mMoreKeysWindow.dismiss(); + mMoreKeysPanel = null; + mMoreKeysPanelPointerTrackerId = -1; invalidateAllKeys(); return true; } @@ -638,7 +627,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } public boolean handleBack() { - return dismissPopupPanel(); + return dismissMoreKeysPanel(); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java index ff4e72853..da91b62d9 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java @@ -20,7 +20,7 @@ import android.graphics.Paint; import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardParams; -import com.android.inputmethod.keyboard.internal.PopupCharactersParser; +import com.android.inputmethod.keyboard.internal.MoreKeySpecParser; import com.android.inputmethod.latin.R; public class MiniKeyboard extends Keyboard { @@ -36,7 +36,7 @@ public class MiniKeyboard extends Keyboard { } public static class Builder extends KeyboardBuilder<Builder.MiniKeyboardParams> { - private final CharSequence[] mPopupCharacters; + private final CharSequence[] mMoreKeys; public static class MiniKeyboardParams extends KeyboardParams { /* package */int mTopRowAdjustment; @@ -224,22 +224,22 @@ public class MiniKeyboard extends Keyboard { // mParams.mVerticalGap = parentKeyboard.mVerticalGap; mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard; - mPopupCharacters = parentKey.mPopupCharacters; + mMoreKeys = parentKey.mMoreKeys; - final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, mParams.mDefaultKeyWidth); - mParams.setParameters(mPopupCharacters.length, parentKey.mMaxPopupColumn, keyWidth, - parentKeyboard.mDefaultRowHeight, parentKey.mX + final int keyWidth = getMaxKeyWidth(view, mMoreKeys, mParams.mDefaultKeyWidth); + mParams.setParameters(mMoreKeys.length, parentKey.mMaxMoreKeysColumn, + keyWidth, parentKeyboard.mDefaultRowHeight, parentKey.mX + (mParams.mDefaultKeyWidth - keyWidth) / 2, view.getMeasuredWidth()); } - private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters, + private static int getMaxKeyWidth(KeyboardView view, CharSequence[] moreKeys, int minKeyWidth) { final int padding = (int) view.getContext().getResources() .getDimension(R.dimen.mini_keyboard_key_horizontal_padding); Paint paint = null; int maxWidth = minKeyWidth; - for (CharSequence popupSpec : popupCharacters) { - final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString()); + for (CharSequence moreKeySpec : moreKeys) { + final CharSequence label = MoreKeySpecParser.getLabel(moreKeySpec.toString()); // If the label is single letter, minKeyWidth is enough to hold // the label. if (label != null && label.length() > 1) { @@ -259,10 +259,10 @@ public class MiniKeyboard extends Keyboard { @Override public MiniKeyboard build() { final MiniKeyboardParams params = mParams; - for (int n = 0; n < mPopupCharacters.length; n++) { - final CharSequence label = mPopupCharacters[n]; + for (int n = 0; n < mMoreKeys.length; n++) { + final String moreKeySpec = mMoreKeys[n].toString(); final int row = n / params.mNumColumns; - final Key key = new Key(mResources, params, label.toString(), params.getX(n, row), + final Key key = new Key(mResources, params, moreKeySpec, params.getX(n, row), params.getY(row), params.mDefaultKeyWidth, params.mDefaultRowHeight, params.getRowFlags(row)); params.onAddKey(key); diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java index 7ace46cac..f331662d7 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java @@ -18,7 +18,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.res.Resources; -import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; @@ -34,11 +33,10 @@ import java.util.List; * A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting * key presses and touch movements. */ -public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { +public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { private final int[] mCoordinates = new int[2]; private final KeyDetector mKeyDetector; - private final int mVerticalCorrection; private Controller mController; private KeyboardActionListener mListener; @@ -90,16 +88,7 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { } } - private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy() { - @Override - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {} - @Override - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {} - @Override - public void cancelLongPressTimer() {} - @Override - public void cancelKeyTimers() {} - }; + private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter(); private final KeyboardActionListener mMiniKeyboardListener = new KeyboardActionListener.Adapter() { @@ -128,19 +117,13 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { } }; - public PopupMiniKeyboardView(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.popupMiniKeyboardViewStyle); + public MiniKeyboardView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.miniKeyboardViewStyle); } - public PopupMiniKeyboardView(Context context, AttributeSet attrs, int defStyle) { + public MiniKeyboardView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - mVerticalCorrection = a.getDimensionPixelOffset( - R.styleable.KeyboardView_verticalCorrection, 0); - a.recycle(); - final Resources res = context.getResources(); // Override default ProximityKeyDetector. mKeyDetector = new MiniKeyboardKeyDetector(res.getDimension( @@ -204,7 +187,7 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { } @Override - public void showPopupPanel(View parentView, Controller controller, int pointX, int pointY, + public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, PopupWindow window, KeyboardActionListener listener) { mController = controller; mListener = listener; @@ -240,8 +223,8 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { } @Override - public boolean dismissPopupPanel() { - return mController.dismissPopupPanel(); + public boolean dismissMoreKeysPanel() { + return mController.dismissMoreKeysPanel(); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/PopupPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java index 5e51fd54a..6314a99db 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupPanel.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java @@ -19,36 +19,41 @@ package com.android.inputmethod.keyboard; import android.view.View; import android.widget.PopupWindow; -public interface PopupPanel extends PointerTracker.KeyEventHandler { +public interface MoreKeysPanel extends PointerTracker.KeyEventHandler { public interface Controller { - public boolean dismissPopupPanel(); + public boolean dismissMoreKeysPanel(); } public void setShifted(boolean shifted); /** - * Show popup panel. - * @param parentView the parent view of this popup panel - * @param controller the controller that can dismiss this popup panel - * @param pointX x coordinate of this popup panel - * @param pointY y coordinate of this popup panel - * @param window PopupWindow to be used to show this popup panel - * @param listener the listener that will receive keyboard action from this popup panel. + * Show more keys panel. + * + * @param parentView the parent view of this more keys panel + * @param controller the controller that can dismiss this more keys panel + * @param pointX x coordinate of this more keys panel + * @param pointY y coordinate of this more keys panel + * @param window PopupWindow to be used to show this more keys panel + * @param listener the listener that will receive keyboard action from this more keys panel. */ - public void showPopupPanel(View parentView, Controller controller, int pointX, int pointY, + public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, PopupWindow window, KeyboardActionListener listener); /** - * Translate X-coordinate of touch event to the local X-coordinate of this PopupPanel. + * Translate X-coordinate of touch event to the local X-coordinate of this + * {@link MoreKeysPanel}. + * * @param x the global X-coordinate - * @return the local X-coordinate to this PopupPanel + * @return the local X-coordinate to this {@link MoreKeysPanel} */ public int translateX(int x); /** - * Translate Y-coordinate of touch event to the local Y-coordinate of this PopupPanel. + * Translate Y-coordinate of touch event to the local Y-coordinate of this + * {@link MoreKeysPanel}. + * * @param y the global Y-coordinate - * @return the local Y-coordinate to this PopupPanel + * @return the local Y-coordinate to this {@link MoreKeysPanel} */ public int translateY(int y); } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 7ae62200d..0314867b3 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -63,7 +63,7 @@ public class PointerTracker { public TimerProxy getTimerProxy(); } - public interface DrawingProxy extends PopupPanel.Controller { + public interface DrawingProxy extends MoreKeysPanel.Controller { public void invalidateKey(Key key); public TextView inflateKeyPreviewText(); public void showKeyPreview(int keyIndex, PointerTracker tracker); @@ -76,6 +76,17 @@ public class PointerTracker { public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker); public void cancelLongPressTimer(); public void cancelKeyTimers(); + + public static class Adapter implements TimerProxy { + @Override + public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {} + @Override + public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {} + @Override + public void cancelLongPressTimer() {} + @Override + public void cancelKeyTimers() {} + } } private static KeyboardSwitcher sKeyboardSwitcher; @@ -123,8 +134,8 @@ public class PointerTracker { // true if event is already translated to a key action. private boolean mKeyAlreadyProcessed; - // true if this pointer has been long-pressed and is showing a popup panel. - private boolean mIsShowingPopupPanel; + // true if this pointer has been long-pressed and is showing a more keys panel. + private boolean mIsShowingMoreKeysPanel; // true if this pointer is repeatable key private boolean mIsRepeatableKey; @@ -572,9 +583,9 @@ public class PointerTracker { } final int keyIndex = onUpKey(keyX, keyY, eventTime); setReleasedKeyGraphics(keyIndex); - if (mIsShowingPopupPanel) { - mDrawingProxy.dismissPopupPanel(); - mIsShowingPopupPanel = false; + if (mIsShowingMoreKeysPanel) { + mDrawingProxy.dismissMoreKeysPanel(); + mIsShowingMoreKeysPanel = false; } if (mKeyAlreadyProcessed) return; @@ -583,10 +594,10 @@ public class PointerTracker { } } - public void onShowPopupPanel(int x, int y, long eventTime, KeyEventHandler handler) { + public void onShowMoreKeysPanel(int x, int y, long eventTime, KeyEventHandler handler) { onLongPressed(); onDownEvent(x, y, eventTime, handler); - mIsShowingPopupPanel = true; + mIsShowingMoreKeysPanel = true; } public void onLongPressed() { @@ -615,9 +626,9 @@ public class PointerTracker { mDrawingProxy.cancelShowKeyPreview(this); setReleasedKeyGraphics(mKeyIndex); mIsInSlidingKeyInput = false; - if (mIsShowingPopupPanel) { - mDrawingProxy.dismissPopupPanel(); - mIsShowingPopupPanel = false; + if (mIsShowingMoreKeysPanel) { + mDrawingProxy.dismissMoreKeysPanel(); + mIsShowingMoreKeysPanel = false; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java index c0dba4173..6d78e8533 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java @@ -166,12 +166,12 @@ public class KeyStyles { readText(keyAttr, R.styleable.Keyboard_Key_keyLabel); readText(keyAttr, R.styleable.Keyboard_Key_keyOutputText); readText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); - readTextArray(keyAttr, R.styleable.Keyboard_Key_popupCharacters); + readTextArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelOption); readInt(keyAttr, R.styleable.Keyboard_Key_keyIcon); readInt(keyAttr, R.styleable.Keyboard_Key_keyIconPreview); readInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted); - readInt(keyAttr, R.styleable.Keyboard_Key_maxPopupKeyboardColumn); + readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn); readBoolean(keyAttr, R.styleable.Keyboard_Key_isFunctional); readBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky); readBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index f599def36..c605debab 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -255,10 +255,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> { mParams.mIsRtlKeyboard = keyboardAttr.getBoolean( R.styleable.Keyboard_isRtlKeyboard, false); - mParams.mPopupKeyboardResId = keyboardAttr.getResourceId( - R.styleable.Keyboard_popupKeyboardTemplate, 0); - mParams.mMaxPopupColumn = keyAttr.getInt( - R.styleable.Keyboard_Key_maxPopupKeyboardColumn, 5); + mParams.mMoreKeysTemplate = keyboardAttr.getResourceId( + R.styleable.Keyboard_moreKeysTemplate, 0); + mParams.mMaxMiniKeyboardColumn = keyAttr.getInt( + R.styleable.Keyboard_Key_maxMoreKeysColumn, 5); mParams.mIconsSet.loadIcons(keyboardAttr); } finally { @@ -365,9 +365,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> { checkEndTag(TAG_KEY, parser); } else { Key key = new Key(mResources, mParams, row, mCurrentX, mCurrentY, parser, mKeyStyles); - if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d popupCharacters=%s />", + if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />", TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode, - Arrays.toString(key.mPopupCharacters))); + Arrays.toString(key.mMoreKeys))); checkEndTag(TAG_KEY, parser); mParams.onAddKey(key); endKey(key); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java index 980115200..4432ee121 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java @@ -49,8 +49,8 @@ public class KeyboardParams { public int mVerticalGap; public boolean mIsRtlKeyboard; - public int mPopupKeyboardResId; - public int mMaxPopupColumn; + public int mMoreKeysTemplate; + public int mMaxMiniKeyboardColumn; public int GRID_WIDTH; public int GRID_HEIGHT; diff --git a/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java index 7c5abe32a..a490b0ad6 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java @@ -26,9 +26,9 @@ import com.android.inputmethod.latin.R; import java.util.ArrayList; /** - * String parser of popupCharacters attribute of Key. - * The string is comma separated texts each of which represents one popup key. - * Each popup key text is one of the following: + * String parser of moreKeys attribute of Key. + * The string is comma separated texts each of which represents one "more key". + * Each "more key" specification is one of the following: * - A single letter (Letter) * - Label optionally followed by keyOutputText or code (keyLabel|keyOutputText). * - Icon followed by keyOutputText or code (@icon/icon_number|@integer/key_code) @@ -37,8 +37,8 @@ import java.util.ArrayList; * Note that the character '@' and '\' are also parsed by XML parser and CSV parser as well. * See {@link KeyboardIconsSet} about icon_number. */ -public class PopupCharactersParser { - private static final String TAG = PopupCharactersParser.class.getSimpleName(); +public class MoreKeySpecParser { + private static final String TAG = MoreKeySpecParser.class.getSimpleName(); private static final char ESCAPE = '\\'; private static final String LABEL_END = "|"; @@ -46,24 +46,24 @@ public class PopupCharactersParser { private static final String PREFIX_ICON = PREFIX_AT + "icon/"; private static final String PREFIX_CODE = PREFIX_AT + "integer/"; - private PopupCharactersParser() { + private MoreKeySpecParser() { // Intentional empty constructor for utility class. } - private static boolean hasIcon(String popupSpec) { - if (popupSpec.startsWith(PREFIX_ICON)) { - final int end = indexOfLabelEnd(popupSpec, 0); + private static boolean hasIcon(String moreKeySpec) { + if (moreKeySpec.startsWith(PREFIX_ICON)) { + final int end = indexOfLabelEnd(moreKeySpec, 0); if (end > 0) return true; - throw new PopupCharactersParserError("outputText or code not specified: " + popupSpec); + throw new MoreKeySpecParserError("outputText or code not specified: " + moreKeySpec); } return false; } - private static boolean hasCode(String popupSpec) { - final int end = indexOfLabelEnd(popupSpec, 0); - if (end > 0 && end + 1 < popupSpec.length() - && popupSpec.substring(end + 1).startsWith(PREFIX_CODE)) { + private static boolean hasCode(String moreKeySpec) { + final int end = indexOfLabelEnd(moreKeySpec, 0); + if (end > 0 && end + 1 < moreKeySpec.length() + && moreKeySpec.substring(end + 1).startsWith(PREFIX_CODE)) { return true; } return false; @@ -85,81 +85,81 @@ public class PopupCharactersParser { return sb.toString(); } - private static int indexOfLabelEnd(String popupSpec, int start) { - if (popupSpec.indexOf(ESCAPE, start) < 0) { - final int end = popupSpec.indexOf(LABEL_END, start); + private static int indexOfLabelEnd(String moreKeySpec, int start) { + if (moreKeySpec.indexOf(ESCAPE, start) < 0) { + final int end = moreKeySpec.indexOf(LABEL_END, start); if (end == 0) - throw new PopupCharactersParserError(LABEL_END + " at " + start + ": " + popupSpec); + throw new MoreKeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec); return end; } - final int length = popupSpec.length(); + final int length = moreKeySpec.length(); for (int pos = start; pos < length; pos++) { - final char c = popupSpec.charAt(pos); + final char c = moreKeySpec.charAt(pos); if (c == ESCAPE && pos + 1 < length) { pos++; - } else if (popupSpec.startsWith(LABEL_END, pos)) { + } else if (moreKeySpec.startsWith(LABEL_END, pos)) { return pos; } } return -1; } - public static String getLabel(String popupSpec) { - if (hasIcon(popupSpec)) + public static String getLabel(String moreKeySpec) { + if (hasIcon(moreKeySpec)) return null; - final int end = indexOfLabelEnd(popupSpec, 0); - final String label = (end > 0) ? parseEscape(popupSpec.substring(0, end)) - : parseEscape(popupSpec); + final int end = indexOfLabelEnd(moreKeySpec, 0); + final String label = (end > 0) ? parseEscape(moreKeySpec.substring(0, end)) + : parseEscape(moreKeySpec); if (TextUtils.isEmpty(label)) - throw new PopupCharactersParserError("Empty label: " + popupSpec); + throw new MoreKeySpecParserError("Empty label: " + moreKeySpec); return label; } - public static String getOutputText(String popupSpec) { - if (hasCode(popupSpec)) + public static String getOutputText(String moreKeySpec) { + if (hasCode(moreKeySpec)) return null; - final int end = indexOfLabelEnd(popupSpec, 0); + final int end = indexOfLabelEnd(moreKeySpec, 0); if (end > 0) { - if (indexOfLabelEnd(popupSpec, end + 1) >= 0) - throw new PopupCharactersParserError("Multiple " + LABEL_END + ": " - + popupSpec); - final String outputText = parseEscape(popupSpec.substring(end + LABEL_END.length())); + if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) + throw new MoreKeySpecParserError("Multiple " + LABEL_END + ": " + + moreKeySpec); + final String outputText = parseEscape(moreKeySpec.substring(end + LABEL_END.length())); if (!TextUtils.isEmpty(outputText)) return outputText; - throw new PopupCharactersParserError("Empty outputText: " + popupSpec); + throw new MoreKeySpecParserError("Empty outputText: " + moreKeySpec); } - final String label = getLabel(popupSpec); + final String label = getLabel(moreKeySpec); if (label == null) - throw new PopupCharactersParserError("Empty label: " + popupSpec); + throw new MoreKeySpecParserError("Empty label: " + moreKeySpec); // Code is automatically generated for one letter label. See {@link getCode()}. if (label.length() == 1) return null; return label; } - public static int getCode(Resources res, String popupSpec) { - if (hasCode(popupSpec)) { - final int end = indexOfLabelEnd(popupSpec, 0); - if (indexOfLabelEnd(popupSpec, end + 1) >= 0) - throw new PopupCharactersParserError("Multiple " + LABEL_END + ": " + popupSpec); + public static int getCode(Resources res, String moreKeySpec) { + if (hasCode(moreKeySpec)) { + final int end = indexOfLabelEnd(moreKeySpec, 0); + if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) + throw new MoreKeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); final int resId = getResourceId(res, - popupSpec.substring(end + LABEL_END.length() + PREFIX_AT.length())); + moreKeySpec.substring(end + LABEL_END.length() + PREFIX_AT.length())); final int code = res.getInteger(resId); return code; } - if (indexOfLabelEnd(popupSpec, 0) > 0) + if (indexOfLabelEnd(moreKeySpec, 0) > 0) return Keyboard.CODE_DUMMY; - final String label = getLabel(popupSpec); + final String label = getLabel(moreKeySpec); // Code is automatically generated for one letter label. if (label != null && label.length() == 1) return label.charAt(0); return Keyboard.CODE_DUMMY; } - public static int getIconId(String popupSpec) { - if (hasIcon(popupSpec)) { - int end = popupSpec.indexOf(LABEL_END, PREFIX_ICON.length() + 1); - final String iconId = popupSpec.substring(PREFIX_ICON.length(), end); + public static int getIconId(String moreKeySpec) { + if (hasIcon(moreKeySpec)) { + int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length() + 1); + final String iconId = moreKeySpec.substring(PREFIX_ICON.length(), end); try { return Integer.valueOf(iconId); } catch (NumberFormatException e) { @@ -174,13 +174,13 @@ public class PopupCharactersParser { String packageName = res.getResourcePackageName(R.string.english_ime_name); int resId = res.getIdentifier(name, null, packageName); if (resId == 0) - throw new PopupCharactersParserError("Unknown resource: " + name); + throw new MoreKeySpecParserError("Unknown resource: " + name); return resId; } @SuppressWarnings("serial") - public static class PopupCharactersParserError extends RuntimeException { - public PopupCharactersParserError(String message) { + public static class MoreKeySpecParserError extends RuntimeException { + public MoreKeySpecParserError(String message) { super(message); } } @@ -196,31 +196,31 @@ public class PopupCharactersParser { } }; - public static CharSequence[] filterOut(Resources res, CharSequence[] popupCharacters, + public static CharSequence[] filterOut(Resources res, CharSequence[] moreKeys, CodeFilter filter) { - if (popupCharacters == null || popupCharacters.length < 1) { + if (moreKeys == null || moreKeys.length < 1) { return null; } - if (popupCharacters.length == 1 - && filter.shouldFilterOut(getCode(res, popupCharacters[0].toString()))) { + if (moreKeys.length == 1 + && filter.shouldFilterOut(getCode(res, moreKeys[0].toString()))) { return null; } ArrayList<CharSequence> filtered = null; - for (int i = 0; i < popupCharacters.length; i++) { - final CharSequence popupSpec = popupCharacters[i]; - if (filter.shouldFilterOut(getCode(res, popupSpec.toString()))) { + for (int i = 0; i < moreKeys.length; i++) { + final CharSequence moreKeySpec = moreKeys[i]; + if (filter.shouldFilterOut(getCode(res, moreKeySpec.toString()))) { if (filtered == null) { filtered = new ArrayList<CharSequence>(); for (int j = 0; j < i; j++) { - filtered.add(popupCharacters[j]); + filtered.add(moreKeys[j]); } } } else if (filtered != null) { - filtered.add(popupSpec); + filtered.add(moreKeySpec); } } if (filtered == null) { - return popupCharacters; + return moreKeys; } if (filtered.size() == 0) { return null; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index e95172d1f..38563be4a 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -25,12 +25,15 @@ import android.net.Uri; import android.text.TextUtils; import android.util.Log; +import java.io.BufferedInputStream; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -46,7 +49,9 @@ public class BinaryDictionaryFileDumper { /** * The size of the temporary buffer to copy files. */ - static final int FILE_READ_BUFFER_SIZE = 1024; + private static final int FILE_READ_BUFFER_SIZE = 1024; + // TODO: make the following data common with the native code + private static final byte[] MAGIC_NUMBER = new byte[] { 0x78, (byte)0xB1 }; private static final String DICTIONARY_PROJECTION[] = { "id" }; @@ -135,6 +140,7 @@ public class BinaryDictionaryFileDumper { for (int mode = MODE_MIN; mode <= MODE_MAX; ++mode) { InputStream originalSourceStream = null; InputStream inputStream = null; + File outputFile = null; FileOutputStream outputStream = null; AssetFileDescriptor afd = null; try { @@ -144,7 +150,8 @@ public class BinaryDictionaryFileDumper { if (null == afd) return null; originalSourceStream = afd.createInputStream(); // Open output. - outputStream = new FileOutputStream(outputFileName); + outputFile = new File(outputFileName); + outputStream = new FileOutputStream(outputFile); // Get the appropriate decryption method for this try switch (mode) { case COMPRESSED_CRYPTED_COMPRESSED: @@ -171,7 +178,7 @@ public class BinaryDictionaryFileDumper { inputStream = originalSourceStream; break; } - copyFileTo(inputStream, outputStream); + checkMagicAndCopyFileTo(new BufferedInputStream(inputStream), outputStream); if (0 >= resolver.delete(wordListUri, null, null)) { Log.e(TAG, "Could not have the dictionary pack delete a word list"); } @@ -181,6 +188,12 @@ public class BinaryDictionaryFileDumper { if (DEBUG) { Log.i(TAG, "Can't open word list in mode " + mode + " : " + e); } + if (null != outputFile) { + // This may or may not fail. The file may not have been created if the + // exception was thrown before it could be. Hence, both failure and + // success are expected outcomes, so we don't check the return value. + outputFile.delete(); + } // Try the next method. } finally { // Ignore exceptions while closing files. @@ -234,12 +247,29 @@ public class BinaryDictionaryFileDumper { } /** - * Copies the data in an input stream to a target file. + * Copies the data in an input stream to a target file if the magic number matches. + * + * If the magic number does not match the expected value, this method throws an + * IOException. Other usual conditions for IOException or FileNotFoundException + * also apply. + * * @param input the stream to be copied. * @param outputFile an outputstream to copy the data to. */ - private static void copyFileTo(final InputStream input, final FileOutputStream output) - throws FileNotFoundException, IOException { + private static void checkMagicAndCopyFileTo(final BufferedInputStream input, + final FileOutputStream output) throws FileNotFoundException, IOException { + // Check the magic number + final byte[] magicNumberBuffer = new byte[MAGIC_NUMBER.length]; + final int readMagicNumberSize = input.read(magicNumberBuffer, 0, MAGIC_NUMBER.length); + if (readMagicNumberSize < MAGIC_NUMBER.length) { + throw new IOException("Less bytes to read than the magic number length"); + } + if (!Arrays.equals(MAGIC_NUMBER, magicNumberBuffer)) { + throw new IOException("Wrong magic number for downloaded file"); + } + output.write(MAGIC_NUMBER); + + // Actually copy the file final byte[] buffer = new byte[FILE_READ_BUFFER_SIZE]; for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer)) output.write(buffer, 0, readBytes); diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index f445abf48..0d355d01e 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -23,6 +23,7 @@ import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Message; +import android.os.SystemClock; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; @@ -34,8 +35,10 @@ 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; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -46,6 +49,9 @@ 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.MoreKeysPanel; +import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.util.ArrayList; @@ -58,18 +64,22 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. - private static final int MAX_SUGGESTIONS = 18; - private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; - private static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT; + public static final int MAX_SUGGESTIONS = 18; private static final boolean DBG = LatinImeLogger.sDBG; private final ViewGroup mCandidatesPlacer; private final ViewGroup mCandidatesStrip; + // TODO: Remove these pane related fields and stuffs. private ViewGroup mCandidatesPane; private ViewGroup mCandidatesPaneContainer; private View mKeyboardView; + private final View mMoreSuggestionsContainer; + private final MoreSuggestionsView mMoreSuggestionsView; + private final MoreSuggestions.Builder mMoreSuggestionsBuilder; + private final PopupWindow mMoreSuggestionsWindow; + private final ArrayList<TextView> mWords = new ArrayList<TextView>(); private final ArrayList<TextView> mInfos = new ArrayList<TextView>(); private final ArrayList<View> mDividers = new ArrayList<View>(); @@ -155,12 +165,13 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo final TextView word = words.get(0); final View divider = dividers.get(0); mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); - divider.measure(WRAP_CONTENT, MATCH_PARENT); + divider.measure( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mDividerWidth = divider.getMeasuredWidth(); mDividerHeight = divider.getMeasuredHeight(); final Resources res = word.getResources(); - mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); + mCandidateStripHeight = res.getDimensionPixelSize(R.dimen.candidate_strip_height); } } @@ -224,7 +235,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo lastView = word; if (x == 0) centeringFrom = word; - word.measure(WRAP_CONTENT, + word.measure(ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.makeMeasureSpec(mCandidateStripHeight, MeasureSpec.EXACTLY)); final int width = word.getMeasuredWidth(); final int height = word.getMeasuredHeight(); @@ -234,7 +245,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo if (info != null) { paneView.addView(info); lastView = info; - info.measure(WRAP_CONTENT, WRAP_CONTENT); + info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); final int infoWidth = info.getMeasuredWidth(); FrameLayoutCompatUtils.placeViewAt( info, x - infoWidth, y, infoWidth, info.getMeasuredHeight()); @@ -257,7 +269,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo private final int mColorTypedWord; private final int mColorAutoCorrect; private final int mColorSuggestedCandidate; - private final int mCandidateCountInStrip; + public final int mCandidateCountInStrip; private final float mCenterCandidateWeight; private final int mCenterCandidateIndex; private final Drawable mMoreCandidateHint; @@ -430,7 +442,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo word.setText(text); // TextView.setText() resets text scale x to 1.0. word.setTextScaleX(scaleX); stripView.addView(word); - setLayoutWeight(word, getCandidateWeight(index), MATCH_PARENT); + setLayoutWeight( + word, getCandidateWeight(index), ViewGroup.LayoutParams.MATCH_PARENT); x += word.getMeasuredWidth(); if (DBG) { @@ -439,7 +452,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo final TextView info = mInfos.get(pos); info.setText(debugInfo); placer.addView(info); - info.measure(WRAP_CONTENT, WRAP_CONTENT); + info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); final int infoWidth = info.getMeasuredWidth(); final int y = info.getMeasuredHeight(); FrameLayoutCompatUtils.placeViewAt( @@ -447,7 +461,6 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } } } - return countInStrip; } @@ -515,7 +528,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo wordView.setText(text); wordView.setTextScaleX(wordScaleX); stripView.addView(wordView); - setLayoutWeight(wordView, mCenterCandidateWeight, MATCH_PARENT); + setLayoutWeight(wordView, mCenterCandidateWeight, ViewGroup.LayoutParams.MATCH_PARENT); stripView.addView(mDividers.get(0)); @@ -526,7 +539,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo hintView.setText(mHintToSaveText); hintView.setTextScaleX(hintScaleX); stripView.addView(hintView); - setLayoutWeight(hintView, 1.0f - mCenterCandidateWeight, MATCH_PARENT); + setLayoutWeight( + hintView, 1.0f - mCenterCandidateWeight, ViewGroup.LayoutParams.MATCH_PARENT); } } @@ -558,7 +572,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mPreviewPopup = new PopupWindow(context); mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); - mPreviewPopup.setWindowLayoutMode(WRAP_CONTENT, WRAP_CONTENT); + mPreviewPopup.setWindowLayoutMode( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); mPreviewPopup.setContentView(mPreviewText); mPreviewPopup.setBackgroundDrawable(null); @@ -581,6 +596,15 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mInfos); mPaneParams = new SuggestionsPaneParams(mWords, mDividers, mInfos); mStripParams.mWordToSaveView.setOnClickListener(this); + + mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); + mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer + .findViewById(R.id.more_suggestions_view); + mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView); + mMoreSuggestionsWindow = new PopupWindow(context); + mMoreSuggestionsWindow.setWindowLayoutMode( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + mMoreSuggestionsWindow.setBackgroundDrawable(null); } /** @@ -617,8 +641,6 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo final int width = getWidth(); final int countInStrip = mStripParams.layout( mSuggestions, mCandidatesStrip, mCandidatesPlacer, width); - mPaneParams.layout( - mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width); } private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { @@ -783,6 +805,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mCandidatesStrip.removeAllViews(); mCandidatesPane.removeAllViews(); closeCandidatesPane(); + mMoreSuggestionsWindow.dismiss(); } private void hidePreview() { @@ -796,8 +819,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo final TextView previewText = mPreviewText; previewText.setTextColor(mStripParams.mColorTypedWord); previewText.setText(word); - previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + previewText.measure( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); final int[] offsetInWindow = new int[2]; view.getLocationInWindow(offsetInWindow); final int posX = offsetInWindow[0]; @@ -819,16 +842,103 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } } + private final KeyboardActionListener mMoreSuggestionsListener = + new KeyboardActionListener.Adapter() { + @Override + public boolean onCustomRequest(int requestCode) { + final int index = requestCode; + final CharSequence word = mSuggestions.getWord(index); + mListener.pickSuggestionManually(index, word); + mMoreSuggestionsView.dismissMoreKeysPanel(); + return true; + } + + @Override + public void onCancelInput() { + mMoreSuggestionsView.dismissMoreKeysPanel(); + } + }; + + private final MoreKeysPanel.Controller mMoreSuggestionsController = + new MoreKeysPanel.Controller() { + @Override + public boolean dismissMoreKeysPanel() { + if (mMoreSuggestionsWindow.isShowing()) { + mMoreSuggestionsWindow.dismiss(); + return true; + } + return false; + } + }; + @Override public boolean onLongClick(View view) { - if (mStripParams.mMoreSuggestionsAvailable) { - toggleCandidatesPane(); + final SuggestionsStripParams params = mStripParams; + if (params.mMoreSuggestionsAvailable) { + final int stripWidth = getWidth(); + 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.mCandidateCountInStrip, maxWidth, maxHeight); + 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; + 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); + view.setPressed(false); + // TODO: Should gray out the keyboard here as well? return true; } return false; } @Override + public boolean dispatchTouchEvent(MotionEvent me) { + if (!mMoreSuggestionsWindow.isShowing()) { + return super.dispatchTouchEvent(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, 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; + } + return true; + } + + @Override public void onClick(View view) { if (view == mStripParams.mWordToSaveView) { addToDictionary((CharSequence)view.getTag()); diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/MoreSuggestions.java new file mode 100644 index 000000000..0446fb2a8 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/MoreSuggestions.java @@ -0,0 +1,203 @@ +/* + * 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.latin; + +import android.graphics.Paint; +import android.text.TextUtils; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.KeyboardView; +import com.android.inputmethod.keyboard.internal.KeyboardBuilder; +import com.android.inputmethod.keyboard.internal.KeyboardParams; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + +public class MoreSuggestions extends Keyboard { + private static final boolean DBG = LatinImeLogger.sDBG; + + public static final int SUGGESTION_CODE_BASE = 1024; + + private MoreSuggestions(Builder.MoreSuggestionsParam params) { + super(params); + } + + public static class Builder extends KeyboardBuilder<Builder.MoreSuggestionsParam> { + private final MoreSuggestionsView mPaneView; + private SuggestedWords mSuggestions; + private int mFromPos; + private int mToPos; + + public static class MoreSuggestionsParam extends KeyboardParams { + private final int[] mWidths = new int[CandidateView.MAX_SUGGESTIONS]; + private final int[] mRowNumbers = new int[CandidateView.MAX_SUGGESTIONS]; + private final int[] mColumnOrders = new int[CandidateView.MAX_SUGGESTIONS]; + private final int[] mNumColumnsInRow = new int[CandidateView.MAX_SUGGESTIONS]; + 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) { + clearKeys(); + final Paint paint = new Paint(); + paint.setAntiAlias(true); + final int padding = (int) view.getContext().getResources() + .getDimension(R.dimen.more_suggestions_key_horizontal_padding); + + int row = 0; + int pos = fromPos, rowStartPos = fromPos; + final int size = Math.min(suggestions.size(), CandidateView.MAX_SUGGESTIONS); + while (pos < size) { + final CharSequence word = suggestions.getWord(pos); + // TODO: Should take care of text x-scaling. + mWidths[pos] = (int)view.getDefaultLabelWidth(word, paint) + padding; + final int numColumn = pos - rowStartPos + 1; + if (numColumn > MAX_COLUMNS_IN_ROW + || !fitInWidth(rowStartPos, pos + 1, maxWidth / numColumn)) { + if ((row + 1) * mDefaultRowHeight > maxHeight) { + break; + } + mNumColumnsInRow[row] = pos - rowStartPos; + rowStartPos = pos; + row++; + } + mColumnOrders[pos] = pos - rowStartPos; + mRowNumbers[pos] = row; + pos++; + } + mNumColumnsInRow[row] = pos - rowStartPos; + mNumRows = row + 1; + mWidth = mOccupiedWidth = calcurateMaxRowWidth(fromPos, pos); + mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap; + return pos - fromPos; + } + + private boolean fitInWidth(int startPos, int endPos, int width) { + for (int pos = startPos; pos < endPos; pos++) { + if (mWidths[pos] > width) + return false; + } + return true; + } + + private int calcurateMaxRowWidth(int startPos, int endPos) { + int maxRowWidth = 0; + int pos = startPos; + for (int row = 0; row < mNumRows; row++) { + final int numColumn = mNumColumnsInRow[row]; + int maxKeyWidth = 0; + while (pos < endPos && mRowNumbers[pos] == row) { + maxKeyWidth = Math.max(maxKeyWidth, mWidths[pos]); + pos++; + } + maxRowWidth = Math.max(maxRowWidth, maxKeyWidth * numColumn); + } + return maxRowWidth; + } + + private static final int[][] COLUMN_ORDER_TO_NUMBER = { + { 0, }, + { 1, 0, }, + { 2, 0, 1}, + }; + + private int getColumnNumber(int pos) { + final int columnOrder = mColumnOrders[pos]; + final int numColumn = mNumColumnsInRow[mRowNumbers[pos]]; + return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder]; + } + + public int getX(int pos) { + final int columnNumber = getColumnNumber(pos); + return columnNumber * getWidth(pos); + } + + public int getY(int pos) { + final int row = mRowNumbers[pos]; + return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding; + } + + public int getWidth(int pos) { + final int row = mRowNumbers[pos]; + final int numColumn = mNumColumnsInRow[row]; + return mWidth / numColumn; + } + + public int getFlags(int pos) { + int rowFlags = 0; + + final int row = mRowNumbers[pos]; + if (row == 0) + rowFlags |= Keyboard.EDGE_BOTTOM; + if (row == mNumRows - 1) + rowFlags |= Keyboard.EDGE_TOP; + + final int numColumn = mNumColumnsInRow[row]; + final int column = getColumnNumber(pos); + if (column == 0) + rowFlags |= Keyboard.EDGE_LEFT; + if (column == numColumn - 1) + rowFlags |= Keyboard.EDGE_RIGHT; + + return rowFlags; + } + } + + public Builder(MoreSuggestionsView paneView) { + super(paneView.getContext(), new MoreSuggestionsParam()); + mPaneView = paneView; + } + + public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth, + int maxHeight) { + 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); + mFromPos = fromPos; + mToPos = fromPos + count; + mSuggestions = suggestions; + return this; + } + + private static String getDebugInfo(SuggestedWords suggestions, int pos) { + if (!DBG) return null; + final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); + if (wordInfo == null) return null; + final String info = wordInfo.getDebugString(); + if (TextUtils.isEmpty(info)) return null; + return info; + } + + @Override + public MoreSuggestions build() { + final MoreSuggestionsParam params = mParams; + for (int pos = mFromPos; pos < mToPos; pos++) { + final String word = mSuggestions.getWord(pos).toString(); + final String info = getDebugInfo(mSuggestions, pos); + final int index = pos + SUGGESTION_CODE_BASE; + final Key key = new Key( + params, word, info, null, index, null, params.getX(pos), params.getY(pos), + params.getWidth(pos), params.mDefaultRowHeight, params.getFlags(pos)); + params.onAddKey(key); + } + return new MoreSuggestions(params); + } + } +} diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java new file mode 100644 index 000000000..828490112 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java @@ -0,0 +1,237 @@ +/* + * 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.latin; + +import android.content.Context; +import android.content.res.Resources; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.PopupWindow; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.keyboard.KeyboardView; +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.TimerProxy; + +import java.util.List; + +/** + * A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting + * key presses and touch movements. + */ +public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { + private final int[] mCoordinates = new int[2]; + + private final KeyDetector mKeyDetector; + + private Controller mController; + private KeyboardActionListener mListener; + private int mOriginX; + private int mOriginY; + + private static class SuggestionsPaneKeyDetector extends KeyDetector { + private final int mSlideAllowanceSquare; + private final int mSlideAllowanceSquareTop; + + public SuggestionsPaneKeyDetector(float slideAllowance) { + super(/* keyHysteresisDistance */0); + mSlideAllowanceSquare = (int)(slideAllowance * slideAllowance); + // Top slide allowance is slightly longer (sqrt(2) times) than other edges. + mSlideAllowanceSquareTop = mSlideAllowanceSquare * 2; + } + + @Override + public boolean alwaysAllowsSlidingInput() { + return true; + } + + @Override + protected int getMaxNearbyKeys() { + // No nearby key will be returned. + return 1; + } + + @Override + public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { + final List<Key> keys = getKeyboard().mKeys; + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); + + int nearestIndex = NOT_A_KEY; + int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; + final int keyCount = keys.size(); + for (int index = 0; index < keyCount; index++) { + final int dist = keys.get(index).squaredDistanceToEdge(touchX, touchY); + if (dist < nearestDist) { + nearestIndex = index; + nearestDist = dist; + } + } + + if (allCodes != null && nearestIndex != NOT_A_KEY) + allCodes[0] = keys.get(nearestIndex).mCode; + return nearestIndex; + } + } + + private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter(); + + private final KeyboardActionListener mSuggestionsPaneListener = + new KeyboardActionListener.Adapter() { + @Override + public void onPress(int primaryCode, boolean withSliding) { + mListener.onPress(primaryCode, withSliding); + } + + @Override + public void onRelease(int primaryCode, boolean withSliding) { + mListener.onRelease(primaryCode, withSliding); + } + + @Override + public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { + mListener.onCustomRequest(primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE); + } + + @Override + public void onCancelInput() { + mListener.onCancelInput(); + } + }; + + public MoreSuggestionsView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.suggestionsPaneViewStyle); + } + + public MoreSuggestionsView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final Resources res = context.getResources(); + // Override default ProximityKeyDetector. + mKeyDetector = new SuggestionsPaneKeyDetector(res.getDimension( + R.dimen.more_suggestions_slide_allowance)); + // Remove gesture detector on suggestions pane + setKeyPreviewPopupEnabled(false, 0); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final Keyboard keyboard = getKeyboard(); + if (keyboard != null) { + final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); + final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); + setMeasuredDimension(width, height); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + public void setKeyboard(Keyboard keyboard) { + super.setKeyboard(keyboard); + mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), + -getPaddingTop() + mVerticalCorrection); + } + + @Override + public KeyDetector getKeyDetector() { + return mKeyDetector; + } + + @Override + public KeyboardActionListener getKeyboardActionListener() { + return mSuggestionsPaneListener; + } + + @Override + public DrawingProxy getDrawingProxy() { + return this; + } + + @Override + public TimerProxy getTimerProxy() { + return EMPTY_TIMER_PROXY; + } + + @Override + public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { + // Suggestions pane needs no pop-up key preview displayed, so we pass always false with a + // delay of 0. The delay does not matter actually since the popup is not shown anyway. + super.setKeyPreviewPopupEnabled(false, 0); + } + + @Override + public void setShifted(boolean shifted) { + // Nothing to do with. + } + + @Override + public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, + PopupWindow window, KeyboardActionListener listener) { + mController = controller; + mListener = listener; + final View container = (View)getParent(); + final MoreSuggestions pane = (MoreSuggestions)getKeyboard(); + + parentView.getLocationInWindow(mCoordinates); + final int paneLeft = pointX - (pane.mOccupiedWidth / 2) + parentView.getPaddingLeft(); + final int x = wrapUp(Math.max(0, Math.min(paneLeft, + parentView.getWidth() - pane.mOccupiedWidth)) + - container.getPaddingLeft() + mCoordinates[0], + container.getMeasuredWidth(), 0, parentView.getWidth()); + final int y = pointY + - (container.getMeasuredHeight() - container.getPaddingBottom()) + + parentView.getPaddingTop() + mCoordinates[1]; + + window.setContentView(container); + window.setWidth(container.getMeasuredWidth()); + window.setHeight(container.getMeasuredHeight()); + window.showAtLocation(parentView, Gravity.NO_GRAVITY, x, y); + + mOriginX = x + container.getPaddingLeft() - mCoordinates[0]; + mOriginY = y + container.getPaddingTop() - mCoordinates[1]; + } + + private static int wrapUp(int x, int width, int left, int right) { + if (x < left) + return left; + if (x + width > right) + return right - width; + return x; + } + + @Override + public boolean dismissMoreKeysPanel() { + return mController.dismissMoreKeysPanel(); + } + + @Override + public int translateX(int x) { + return x - mOriginX; + } + + @Override + public int translateY(int y) { + return y - mOriginY; + } +} diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index a5eed9015..1e2ef4824 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -73,7 +73,6 @@ public class Settings extends InputMethodSettingsActivity public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold"; public static final String PREF_DEBUG_SETTINGS = "debug_settings"; - public static final String PREF_NGRAM_SETTINGS_KEY = "ngram_settings"; public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion"; public static final String PREF_BIGRAM_PREDICTIONS = "bigram_prediction"; @@ -337,7 +336,9 @@ public class Settings extends InputMethodSettingsActivity R.string.auto_correction_threshold_mode_index_off); final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); mBigramSuggestion.setEnabled(!currentSetting.equals(autoCorrectionOff)); - mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); + if (null != mBigramPrediction) { + mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); + } } public Activity getActivityInternal() { |