diff options
Diffstat (limited to 'java/src')
8 files changed, 274 insertions, 172 deletions
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 4995727da..bd73c6fb8 100755 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -237,6 +237,8 @@ public class CandidateView extends View { final boolean typedWordValid = mTypedWordValid; final int y = (int) (height + mPaint.getTextSize() - mDescent) / 2; + boolean existsAutoCompletion = false; + for (int i = 0; i < count; i++) { CharSequence suggestion = mSuggestions.get(i); if (suggestion == null) continue; @@ -245,6 +247,7 @@ public class CandidateView extends View { && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) { paint.setTypeface(Typeface.DEFAULT_BOLD); paint.setColor(mColorRecommended); + existsAutoCompletion = true; } else if (i != 0) { paint.setColor(mColorOther); } @@ -285,6 +288,7 @@ public class CandidateView extends View { paint.setTypeface(Typeface.DEFAULT); x += wordWidth; } + mService.onAutoCompletionStateChanged(existsAutoCompletion); mTotalWidth = x; if (mTargetScrollX != scrollX) { scrollToTarget(); diff --git a/java/src/com/android/inputmethod/latin/KeyDetector.java b/java/src/com/android/inputmethod/latin/KeyDetector.java index 11d5f861d..e443f272b 100644 --- a/java/src/com/android/inputmethod/latin/KeyDetector.java +++ b/java/src/com/android/inputmethod/latin/KeyDetector.java @@ -19,18 +19,23 @@ package com.android.inputmethod.latin; import android.inputmethodservice.Keyboard; import android.inputmethodservice.Keyboard.Key; +import java.util.Arrays; import java.util.List; abstract class KeyDetector { protected Keyboard mKeyboard; - protected Key[] mKeys; + private Key[] mKeys; + protected int mCorrectionX; + protected int mCorrectionY; protected boolean mProximityCorrectOn; protected int mProximityThresholdSquare; - public Key[] setKeyboard(Keyboard keyboard) { + public Key[] setKeyboard(Keyboard keyboard, float correctionX, float correctionY) { if (keyboard == null) throw new NullPointerException(); + mCorrectionX = (int)correctionX; + mCorrectionY = (int)correctionY; mKeyboard = keyboard; List<Key> keys = mKeyboard.getKeys(); Key[] array = keys.toArray(new Key[keys.size()]); @@ -38,6 +43,21 @@ abstract class KeyDetector { return array; } + protected int getTouchX(int x) { + return x + mCorrectionX; + } + + protected int getTouchY(int y) { + return y + mCorrectionY; + } + + protected Key[] getKeys() { + if (mKeys == null) + throw new IllegalStateException("keyboard isn't set"); + // mKeyboard is guaranteed not null at setKeybaord() method + return mKeys; + } + public void setProximityCorrectionEnabled(boolean enabled) { mProximityCorrectOn = enabled; } @@ -50,7 +70,13 @@ abstract class KeyDetector { mProximityThresholdSquare = threshold * threshold; } - abstract public int[] newCodeArray(); + public int[] newCodeArray() { + int[] codes = new int[getMaxNearbyKeys()]; + Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY); + return codes; + } + + abstract protected int getMaxNearbyKeys(); abstract public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys); }
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java index 9c0a5a3aa..2919e9b56 100644 --- a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java @@ -88,6 +88,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private int mMode = MODE_NONE; /** One of the MODE_XXX values */ private int mImeOptions; private boolean mIsSymbols; + /** mIsAutoCompletionActive indicates that auto completed word will be input instead of + * what user actually typed. */ + private boolean mIsAutoCompletionActive; private boolean mHasVoice; private boolean mVoiceOnPrimary; private boolean mPreferSymbols; @@ -239,7 +242,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha keyboard.setShifted(false); keyboard.setShiftLocked(keyboard.isShiftLocked()); keyboard.setImeOptions(mContext.getResources(), mMode, imeOptions); - keyboard.setBlackFlag(isBlackSym()); + keyboard.setColorOfSymbolIcons(mIsAutoCompletionActive, isBlackSym()); } private LatinKeyboard getKeyboard(KeyboardId id) { @@ -249,12 +252,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha Locale saveLocale = conf.locale; conf.locale = mInputLocale; orig.updateConfiguration(conf, null); - LatinKeyboard keyboard = new LatinKeyboard( - mContext, id.mXml, id.mKeyboardMode); + LatinKeyboard keyboard = new LatinKeyboard(mContext, id.mXml, id.mKeyboardMode); keyboard.setVoiceMode(hasVoiceButton(id.mXml == R.xml.kbd_symbols || id.mXml == R.xml.kbd_symbols_black), mHasVoice); - keyboard.setLanguageSwitcher(mLanguageSwitcher); - keyboard.setBlackFlag(isBlackSym()); + keyboard.setLanguageSwitcher(mLanguageSwitcher, mIsAutoCompletionActive, isBlackSym()); if (id.mEnableShiftLock) { keyboard.enableShiftLock(); @@ -450,4 +451,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } } + public void onAutoCompletionStateChanged(boolean isAutoCompletion) { + if (isAutoCompletion != mIsAutoCompletionActive) { + LatinKeyboardView keyboardView = getInputView(); + mIsAutoCompletionActive = isAutoCompletion; + keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard()) + .onAutoCompletionStateChanged(isAutoCompletion)); + } + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 7afee3fad..d0e6e69c7 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2483,4 +2483,7 @@ public class LatinIME extends InputMethodService System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total)); } + public void onAutoCompletionStateChanged(boolean isAutoCompletion) { + mKeyboardSwitcher.onAutoCompletionStateChanged(isAutoCompletion); + } } diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboard.java b/java/src/com/android/inputmethod/latin/LatinKeyboard.java index 33519e4be..b7c4fc4dc 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboard.java @@ -43,11 +43,13 @@ public class LatinKeyboard extends Keyboard { private static final boolean DEBUG_PREFERRED_LETTER = false; private static final String TAG = "LatinKeyboard"; + private static final int OPACITY_FULLY_OPAQUE = 255; private Drawable mShiftLockIcon; private Drawable mShiftLockPreviewIcon; private Drawable mOldShiftIcon; private Drawable mSpaceIcon; + private Drawable mSpaceAutoCompletionIndicator; private Drawable mSpacePreviewIcon; private Drawable mMicIcon; private Drawable mMicPreviewIcon; @@ -111,6 +113,7 @@ public class LatinKeyboard extends Keyboard { mShiftLockPreviewIcon.getIntrinsicWidth(), mShiftLockPreviewIcon.getIntrinsicHeight()); mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space); + mSpaceAutoCompletionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led); mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space); mMicIcon = res.getDrawable(R.drawable.sym_keyboard_mic); mMicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_mic); @@ -277,9 +280,9 @@ public class LatinKeyboard extends Keyboard { return mIsAlphaKeyboard; } - public void setBlackFlag(boolean f) { - mIsBlackSym = f; - if (f) { + public void setColorOfSymbolIcons(boolean isAutoCompletion, boolean isBlack) { + mIsBlackSym = isBlack; + if (isBlack) { mShiftLockIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_shift_locked); mSpaceIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_space); mMicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_mic); @@ -292,8 +295,7 @@ public class LatinKeyboard extends Keyboard { } updateF1Key(); if (mSpaceKey != null) { - mSpaceKey.icon = mSpaceIcon; - updateSpaceBarForLocale(f); + updateSpaceBarForLocale(isAutoCompletion, isBlack); } } @@ -334,23 +336,34 @@ public class LatinKeyboard extends Keyboard { } } - private void updateSpaceBarForLocale(boolean isBlack) { + /** + * @return a key which should be invalidated. + */ + public Key onAutoCompletionStateChanged(boolean isAutoCompletion) { + updateSpaceBarForLocale(isAutoCompletion, mIsBlackSym); + return mSpaceKey; + } + + private void updateSpaceBarForLocale(boolean isAutoCompletion, boolean isBlack) { if (mLocale != null) { - // Create the graphic for spacebar - Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(), - Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(buffer); - drawSpaceBar(canvas, buffer.getWidth(), buffer.getHeight(), 255, isBlack); + Bitmap buffer = drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion, isBlack); mSpaceKey.icon = new BitmapDrawable(mRes, buffer); mSpaceKey.repeatable = mLanguageSwitcher.getLocaleCount() < 2; } else { - mSpaceKey.icon = isBlack ? mRes.getDrawable(R.drawable.sym_bkeyboard_space) - : mRes.getDrawable(R.drawable.sym_keyboard_space); + // sym_keyboard_space_led can be shared with Black and White symbol themes. + mSpaceKey.icon = + isAutoCompletion ? mRes.getDrawable(R.drawable.sym_keyboard_space_led) + : isBlack ? mRes.getDrawable(R.drawable.sym_bkeyboard_space) + : mRes.getDrawable(R.drawable.sym_keyboard_space); mSpaceKey.repeatable = true; } } - private void drawSpaceBar(Canvas canvas, int width, int height, int opacity, boolean isBlack) { + private Bitmap drawSpaceBar(int opacity, boolean isAutoCompletion, boolean isBlack) { + int width = mSpaceKey.width; + int height = mSpaceIcon.getIntrinsicHeight(); + Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(buffer); canvas.drawColor(mRes.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR); Paint paint = new Paint(); paint.setAntiAlias(true); @@ -380,11 +393,22 @@ public class LatinKeyboard extends Keyboard { (mSpaceKey.width + bounds.right) / 2, (int) paint.getTextSize()); } // Draw the spacebar icon at the bottom - int x = (width - mSpaceIcon.getIntrinsicWidth()) / 2; - int y = height - mSpaceIcon.getIntrinsicHeight(); - mSpaceIcon.setBounds(x, y, - x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight()); - mSpaceIcon.draw(canvas); + if (isAutoCompletion) { + final int iconWidth = mSpaceAutoCompletionIndicator.getIntrinsicWidth(); + final int iconHeight = mSpaceAutoCompletionIndicator.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + mSpaceAutoCompletionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight); + mSpaceAutoCompletionIndicator.draw(canvas); + } else { + final int iconWidth = mSpaceIcon.getIntrinsicWidth(); + final int iconHeight = mSpaceIcon.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight); + mSpaceIcon.draw(canvas); + } + return buffer; } private void drawButtonArrow(Drawable arrow, Canvas canvas, int x, int bottomY) { @@ -438,7 +462,8 @@ public class LatinKeyboard extends Keyboard { return mSpaceDragLastDiff > 0 ? 1 : -1; } - public void setLanguageSwitcher(LanguageSwitcher switcher) { + public void setLanguageSwitcher(LanguageSwitcher switcher, boolean isAutoCompletion, + boolean isBlackSym) { mLanguageSwitcher = switcher; Locale locale = mLanguageSwitcher.getLocaleCount() > 0 ? mLanguageSwitcher.getInputLocale() @@ -450,9 +475,9 @@ public class LatinKeyboard extends Keyboard { .equalsIgnoreCase(locale.getLanguage())) { locale = null; } + setColorOfSymbolIcons(isAutoCompletion, isBlackSym); if (mLocale != null && mLocale.equals(locale)) return; mLocale = locale; - updateSpaceBarForLocale(mIsBlackSym); } boolean isCurrentlyInSpace() { @@ -729,7 +754,7 @@ public class LatinKeyboard extends Keyboard { mTextPaint.setTextSize(textSize); mTextPaint.setColor(R.color.latinkeyboard_transparent); mTextPaint.setTextAlign(Align.CENTER); - mTextPaint.setAlpha(255); + mTextPaint.setAlpha(OPACITY_FULLY_OPAQUE); mTextPaint.setAntiAlias(true); mAscent = (int) mTextPaint.ascent(); mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2; diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java index 30042d8a1..ba901eddb 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java @@ -62,8 +62,7 @@ import java.util.Map; * @attr ref R.styleable#LatinKeyboardBaseView_verticalCorrection * @attr ref R.styleable#LatinKeyboardBaseView_popupLayout */ -public class LatinKeyboardBaseView extends View implements View.OnClickListener, - PointerTracker.UIProxy { +public class LatinKeyboardBaseView extends View implements PointerTracker.UIProxy { private static final String TAG = "LatinKeyboardBaseView"; private static final boolean DEBUG = false; @@ -165,7 +164,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, private float mShadowRadius; private Drawable mKeyBackground; private float mBackgroundDimAmount; - private int mVerticalCorrection; + private float mVerticalCorrection; private int mPreviewOffset; private int mPreviewHeight; private int mPopupLayout; @@ -185,17 +184,18 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, private boolean mShowTouchPoints = true; private int mPopupPreviewX; private int mPopupPreviewY; + private int mPopupPreviewOffsetX; + private int mPopupPreviewOffsetY; private int mWindowY; // Popup mini keyboard - private PopupWindow mPopupKeyboard; - private View mMiniKeyboardContainer; + private PopupWindow mMiniKeyboardPopup; private LatinKeyboardBaseView mMiniKeyboard; - private boolean mMiniKeyboardOnScreen; - private View mPopupParent; - private int mMiniKeyboardOffsetX; - private int mMiniKeyboardOffsetY; + private View mMiniKeyboardParent; private Map<Key,View> mMiniKeyboardCache; + private int mMiniKeyboardOriginX; + private int mMiniKeyboardOriginY; + private long mMiniKeyboardPopupTime; private int[] mWindowOffset; /** Listener for {@link OnKeyboardActionListener}. */ @@ -254,9 +254,11 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, startKeyRepeatTimer(REPEAT_INTERVAL, msg.arg1, tracker); break; } - case MSG_LONGPRESS_KEY: - openPopupIfRequired(msg.arg1); + case MSG_LONGPRESS_KEY: { + final PointerTracker tracker = (PointerTracker)msg.obj; + openPopupIfRequired(msg.arg1, tracker); break; + } } } @@ -299,9 +301,9 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, return mInKeyRepeat; } - public void startLongPressTimer(int keyIndex, long delay) { + public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { removeMessages(MSG_LONGPRESS_KEY); - sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0), delay); + sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); } public void cancelLongPressTimer() { @@ -443,10 +445,10 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, mShowPreview = false; } mPreviewPopup.setTouchable(false); - mPopupParent = this; + mMiniKeyboardParent = this; - mPopupKeyboard = new PopupWindow(context); - mPopupKeyboard.setBackgroundDrawable(null); + mMiniKeyboardPopup = new PopupWindow(context); + mMiniKeyboardPopup.setBackgroundDrawable(null); mPaint = new Paint(); mPaint.setAntiAlias(true); @@ -539,7 +541,8 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, mHandler.cancelPopupPreview(); mKeyboard = keyboard; LatinImeLogger.onSetKeyboard(keyboard); - mKeys = mKeyDetector.setKeyboard(keyboard); + mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), + -getPaddingTop() + mVerticalCorrection); for (PointerTracker tracker : mPointerTrackers) { tracker.setKeyboard(mKeys, mDebounceHysteresis); } @@ -611,16 +614,13 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, return mSymbolColorScheme; } - public void setVerticalCorrection(int verticalOffset) { - } - public void setPopupParent(View v) { - mPopupParent = v; + mMiniKeyboardParent = v; } public void setPopupOffset(int x, int y) { - mMiniKeyboardOffsetX = x; - mMiniKeyboardOffsetY = y; + mPopupPreviewOffsetX = x; + mPopupPreviewOffsetY = y; if (mPreviewPopup.isShowing()) { mPreviewPopup.dismiss(); } @@ -643,14 +643,6 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, return mKeyDetector.isProximityCorrectionEnabled(); } - /** - * Popup keyboard close button clicked. - * @hide - */ - public void onClick(View v) { - dismissPopupKeyboard(); - } - protected CharSequence adjustCase(CharSequence label) { if (mKeyboard.isShifted() && label != null && label.length() < 3 && Character.isLowerCase(label.charAt(0))) { @@ -805,7 +797,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, } mInvalidatedKey = null; // Overlay a dark rectangle to dim the keyboard - if (mMiniKeyboardOnScreen) { + if (mMiniKeyboard != null) { paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); canvas.drawRect(0, 0, getWidth(), getHeight(), paint); } @@ -896,8 +888,8 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, if (mOffsetInWindow == null) { mOffsetInWindow = new int[2]; getLocationInWindow(mOffsetInWindow); - mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero - mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero + mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero + mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero int[] mWindowLocation = new int[2]; getLocationOnScreen(mWindowLocation); mWindowY = mWindowLocation[1]; @@ -926,7 +918,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, } else { previewPopup.setWidth(popupWidth); previewPopup.setHeight(popupHeight); - previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, + previewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY, mPopupPreviewX, mPopupPreviewY); } mPreviewText.setVisibility(VISIBLE); @@ -962,18 +954,18 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop()); } - private boolean openPopupIfRequired(int keyIndex) { + private boolean openPopupIfRequired(int keyIndex, PointerTracker tracker) { // Check if we have a popup layout specified first. if (mPopupLayout == 0) { return false; } - if (keyIndex < 0 || keyIndex >= mKeys.length) { - return false; - } - Key popupKey = mKeys[keyIndex]; + Key popupKey = tracker.getKey(keyIndex); + if (popupKey == null) + return false; boolean result = onLongPress(popupKey); if (result) { + tracker.setAlreadyProcessed(); dismissKeyPreview(); } return result; @@ -990,15 +982,13 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, int popupKeyboardId = popupKey.popupResId; if (popupKeyboardId != 0) { - mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey); - if (mMiniKeyboardContainer == null) { + View container = mMiniKeyboardCache.get(popupKey); + if (container == null) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); - mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null); - mMiniKeyboard = (LatinKeyboardBaseView) mMiniKeyboardContainer.findViewById( + container = inflater.inflate(mPopupLayout, null); + mMiniKeyboard = (LatinKeyboardBaseView) container.findViewById( R.id.LatinKeyboardBaseView); - View closeButton = mMiniKeyboardContainer.findViewById(R.id.closeButton); - if (closeButton != null) closeButton.setOnClickListener(this); mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { public void onKey(int primaryCode, int[] keyCodes, int x, int y) { mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y); @@ -1021,7 +1011,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, mKeyboardActionListener.onRelease(primaryCode); } }); - //mInputView.setSuggest(mSuggest); + Keyboard keyboard; if (popupKey.popupCharacters != null) { keyboard = new Keyboard(getContext(), popupKeyboardId, @@ -1031,50 +1021,54 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, } mMiniKeyboard.setKeyboard(keyboard); mMiniKeyboard.setPopupParent(this); - mMiniKeyboardContainer.measure( + container.measure( MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); - mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer); + mMiniKeyboardCache.put(popupKey, container); } else { - mMiniKeyboard = (LatinKeyboardBaseView) mMiniKeyboardContainer.findViewById( + mMiniKeyboard = (LatinKeyboardBaseView) container.findViewById( R.id.LatinKeyboardBaseView); } if (mWindowOffset == null) { mWindowOffset = new int[2]; getLocationInWindow(mWindowOffset); } - int popupX = popupKey.x + getPaddingLeft(); + int popupX = popupKey.x + popupKey.width + getPaddingLeft(); int popupY = popupKey.y + getPaddingTop(); - popupX = popupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth(); - popupY = popupY - mMiniKeyboardContainer.getMeasuredHeight(); - final int x = popupX + mMiniKeyboardContainer.getPaddingRight() + mWindowOffset[0]; - final int y = popupY + mMiniKeyboardContainer.getPaddingBottom() + mWindowOffset[1]; - mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y); + popupX -= container.getMeasuredWidth(); + popupY -= container.getMeasuredHeight(); + popupX += mWindowOffset[0]; + popupY += mWindowOffset[1]; + final int x = popupX + container.getPaddingRight(); + final int y = popupY + container.getPaddingBottom(); + mMiniKeyboardOriginX = (x < 0 ? 0 : x) + container.getPaddingLeft(); + mMiniKeyboardOriginY = y + container.getPaddingTop(); + mMiniKeyboard.setPopupOffset((x < 0) ? 0 : x, y); mMiniKeyboard.setShifted(isShifted()); - mPopupKeyboard.setContentView(mMiniKeyboardContainer); - mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth()); - mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight()); - mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); - mMiniKeyboardOnScreen = true; - //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me)); + mMiniKeyboard.setPreviewEnabled(isPreviewEnabled()); + mMiniKeyboardPopup.setContentView(container); + mMiniKeyboardPopup.setWidth(container.getMeasuredWidth()); + mMiniKeyboardPopup.setHeight(container.getMeasuredHeight()); + mMiniKeyboardPopup.showAtLocation(this, Gravity.NO_GRAVITY, x, y); + + // Inject down event on the key to mini keyboard. + long eventTime = System.currentTimeMillis(); + mMiniKeyboardPopupTime = eventTime; + MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, + popupKey.x + popupKey.width / 2, popupKey.y + popupKey.height / 2, eventTime); + mMiniKeyboard.onTouchEvent(downEvent); + downEvent.recycle(); + invalidateAllKeys(); return true; } return false; } - // TODO: Should cleanup after refactoring mini-keyboard. - public boolean isMiniKeyboardOnScreen() { - return mMiniKeyboardOnScreen; - } - - private int getTouchX(float x) { - return (int)x - getPaddingLeft(); - } - - private int getTouchY(float y) { - return (int)y + mVerticalCorrection - getPaddingTop(); + private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) { + return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action, + x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0); } private PointerTracker getPointerTracker(final int id) { @@ -1106,7 +1100,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, mSwipeTracker.addMovement(me); // We must disable gesture detector while mini-keyboard is on the screen. - if (!mMiniKeyboardOnScreen && mGestureDetector.onTouchEvent(me)) { + if (mMiniKeyboard == null && mGestureDetector.onTouchEvent(me)) { dismissKeyPreview(); mHandler.cancelKeyTimers(); return true; @@ -1114,7 +1108,11 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, // Needs to be called after the gesture detector gets a turn, as it may have // displayed the mini keyboard - if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) { + if (mMiniKeyboard != null) { + MotionEvent translated = generateMiniKeyboardMotionEvent(action, (int)me.getX(), + (int)me.getY(), eventTime); + mMiniKeyboard.onTouchEvent(translated); + translated.recycle(); return true; } @@ -1131,29 +1129,29 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, if (action == MotionEvent.ACTION_MOVE) { for (int index = 0; index < pointerCount; index++) { - int touchX = getTouchX(me.getX(index)); - int touchY = getTouchY(me.getY(index)); + int x = (int)me.getX(index); + int y = (int)me.getY(index); int id = me.getPointerId(index); PointerTracker tracker = getPointerTracker(id); - tracker.onMoveEvent(touchX, touchY, eventTime); + tracker.onMoveEvent(x, y, eventTime); } } else { int index = me.getActionIndex(); - int touchX = getTouchX(me.getX(index)); - int touchY = getTouchY(me.getY(index)); + int x = (int)me.getX(index); + int y = (int)me.getY(index); int id = me.getPointerId(index); PointerTracker tracker = getPointerTracker(id); switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: - onDownEvent(tracker, touchX, touchY, eventTime); + onDownEvent(tracker, x, y, eventTime); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: - onUpEvent(tracker, touchX, touchY, eventTime); + onUpEvent(tracker, x, y, eventTime); break; case MotionEvent.ACTION_CANCEL: - onCancelEvent(tracker, touchX, touchY, eventTime); + onCancelEvent(tracker, x, y, eventTime); break; } } @@ -1161,12 +1159,12 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, return true; } - private void onDownEvent(PointerTracker tracker, int touchX, int touchY, long eventTime) { - tracker.onDownEvent(touchX, touchY, eventTime); + private void onDownEvent(PointerTracker tracker, int x, int y, long eventTime) { + tracker.onDownEvent(x, y, eventTime); mPointerQueue.add(tracker); } - private void onUpEvent(PointerTracker tracker, int touchX, int touchY, long eventTime) { + private void onUpEvent(PointerTracker tracker, int x, int y, long eventTime) { int index = mPointerQueue.lastIndexOf(tracker); if (index >= 0) { mPointerQueue.releasePointersOlderThan(tracker, eventTime); @@ -1174,12 +1172,12 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, Log.w(TAG, "onUpEvent: corresponding down event not found for pointer " + tracker.mPointerId); } - tracker.onUpEvent(touchX, touchY, eventTime); + tracker.onUpEvent(x, y, eventTime); mPointerQueue.remove(tracker); } - private void onCancelEvent(PointerTracker tracker, int touchX, int touchY, long eventTime) { - tracker.onCancelEvent(touchX, touchY, eventTime); + private void onCancelEvent(PointerTracker tracker, int x, int y, long eventTime) { + tracker.onCancelEvent(x, y, eventTime); mPointerQueue.remove(tracker); } @@ -1217,16 +1215,18 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener, closing(); } - public void dismissPopupKeyboard() { - if (mPopupKeyboard.isShowing()) { - mPopupKeyboard.dismiss(); - mMiniKeyboardOnScreen = false; + private void dismissPopupKeyboard() { + if (mMiniKeyboardPopup.isShowing()) { + mMiniKeyboardPopup.dismiss(); + mMiniKeyboard = null; + mMiniKeyboardOriginX = 0; + mMiniKeyboardOriginY = 0; invalidateAllKeys(); } } public boolean handleBack() { - if (mPopupKeyboard.isShowing()) { + if (mMiniKeyboardPopup.isShowing()) { dismissPopupKeyboard(); return true; } diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java index 10f51bd48..a4447d58b 100644 --- a/java/src/com/android/inputmethod/latin/PointerTracker.java +++ b/java/src/com/android/inputmethod/latin/PointerTracker.java @@ -27,13 +27,11 @@ import android.view.ViewConfiguration; public class PointerTracker { private static final String TAG = "PointerTracker"; private static final boolean DEBUG = false; + private static final boolean DEBUG_MOVE = DEBUG && true; public interface UIProxy { public void invalidateKey(Key key); public void showPreview(int keyIndex, PointerTracker tracker); - // TODO: These methods might be temporary. - public void dismissPopupKeyboard(); - public boolean isMiniKeyboardOnScreen(); } public final int mPointerId; @@ -60,6 +58,10 @@ public class PointerTracker { private int mCurrentKey = NOT_A_KEY; private int mStartX; private int mStartY; + private long mDownTime; + + // true if event is already translated to a key action (long press or mini-keyboard) + private boolean mKeyAlreadyProcessed; // for move de-bouncing private int mLastCodeX; @@ -138,12 +140,18 @@ public class PointerTracker { } } - public void onDownEvent(int touchX, int touchY, long eventTime) { - int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); + public void setAlreadyProcessed() { + mKeyAlreadyProcessed = true; + } + + public void onDownEvent(int x, int y, long eventTime) { + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); mCurrentKey = keyIndex; - mStartX = touchX; - mStartY = touchY; - startMoveDebouncing(touchX, touchY); + mStartX = x; + mStartY = y; + mDownTime = eventTime; + mKeyAlreadyProcessed = false; + startMoveDebouncing(x, y); startTimeDebouncing(eventTime); checkMultiTap(eventTime, keyIndex); if (mListener != null) { @@ -155,32 +163,44 @@ public class PointerTracker { repeatKey(keyIndex); mHandler.startKeyRepeatTimer(REPEAT_START_DELAY, keyIndex, this); } - mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT); + mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); } showKeyPreviewAndUpdateKey(keyIndex); - updateMoveDebouncing(touchX, touchY); + updateMoveDebouncing(x, y); if (DEBUG) - Log.d(TAG, "onDownEvent: [" + mPointerId + "] modifier=" + isModifier()); + debugLog("onDownEvent:", x, y); } - public void onMoveEvent(int touchX, int touchY, long eventTime) { - int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); + public void onMoveEvent(int x, int y, long eventTime) { + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); if (isValidKeyIndex(keyIndex)) { if (mCurrentKey == NOT_A_KEY) { updateTimeDebouncing(eventTime); mCurrentKey = keyIndex; - mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT); - } else if (isMinorMoveBounce(touchX, touchY, keyIndex, mCurrentKey)) { + mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); + } else if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { updateTimeDebouncing(eventTime); } else { resetMultiTap(); resetTimeDebouncing(eventTime, mCurrentKey); resetMoveDebouncing(); mCurrentKey = keyIndex; - mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT); + mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); } } else { - mHandler.cancelLongPressTimer(); + if (mCurrentKey != NOT_A_KEY) { + updateTimeDebouncing(eventTime); + mCurrentKey = keyIndex; + mHandler.cancelLongPressTimer(); + } else if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { + updateTimeDebouncing(eventTime); + } else { + resetMultiTap(); + resetTimeDebouncing(eventTime, mCurrentKey); + resetMoveDebouncing(); + mCurrentKey = keyIndex; + mHandler.cancelLongPressTimer(); + } } /* * While time debouncing is in effect, mCurrentKey holds the new key and this tracker @@ -189,17 +209,19 @@ public class PointerTracker { * should not be showed as popup preview. */ showKeyPreviewAndUpdateKey(isMinorTimeBounce() ? mLastKey : mCurrentKey); - updateMoveDebouncing(touchX, touchY); + updateMoveDebouncing(x, y); + if (DEBUG_MOVE) + debugLog("onMoveEvent:", x, y); } - public void onUpEvent(int touchX, int touchY, long eventTime) { + public void onUpEvent(int x, int y, long eventTime) { if (DEBUG) - Log.d(TAG, "onUpEvent: [" + mPointerId + "] modifier=" + isModifier()); - int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); + debugLog("onUpEvent :", x, y); + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); boolean wasInKeyRepeat = mHandler.isInKeyRepeat(); mHandler.cancelKeyTimers(); mHandler.cancelPopupPreview(); - if (isMinorMoveBounce(touchX, touchY, keyIndex, mCurrentKey)) { + if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { updateTimeDebouncing(eventTime); } else { resetMultiTap(); @@ -208,24 +230,23 @@ public class PointerTracker { } if (isMinorTimeBounce()) { mCurrentKey = mLastKey; - touchX = mLastCodeX; - touchY = mLastCodeY; + x = mLastCodeX; + y = mLastCodeY; } showKeyPreviewAndUpdateKey(NOT_A_KEY); // If we're not on a repeating key (which sends on a DOWN event) - if (!wasInKeyRepeat && !mProxy.isMiniKeyboardOnScreen()) { - detectAndSendKey(mCurrentKey, touchX, touchY, eventTime); + if (!wasInKeyRepeat && !mKeyAlreadyProcessed) { + detectAndSendKey(mCurrentKey, (int)x, (int)y, eventTime); } if (isValidKeyIndex(keyIndex)) mProxy.invalidateKey(mKeys[keyIndex]); } - public void onCancelEvent(int touchX, int touchY, long eventTime) { + public void onCancelEvent(int x, int y, long eventTime) { if (DEBUG) - Log.d(TAG, "onCancelEvent: [" + mPointerId + "]"); + debugLog("onCancelEvt:", x, y); mHandler.cancelKeyTimers(); mHandler.cancelPopupPreview(); - mProxy.dismissPopupKeyboard(); showKeyPreviewAndUpdateKey(NOT_A_KEY); int keyIndex = mCurrentKey; if (isValidKeyIndex(keyIndex)) @@ -241,6 +262,18 @@ public class PointerTracker { } } + public int getLastX() { + return mLastX; + } + + public int getLastY() { + return mLastY; + } + + public long getDownTime() { + return mDownTime; + } + // These package scope methods are only for debugging purpose. /* package */ int getStartX() { return mStartX; @@ -250,14 +283,6 @@ public class PointerTracker { return mStartY; } - /* package */ int getLastX() { - return mLastX; - } - - /* package */ int getLastY() { - return mLastY; - } - private void startMoveDebouncing(int x, int y) { mLastCodeX = x; mLastCodeY = y; @@ -412,4 +437,17 @@ public class PointerTracker { resetMultiTap(); } } + + private void debugLog(String title, int x, int y) { + Key key = getKey(mCurrentKey); + final String code; + if (key == null) { + code = "----"; + } else { + int primaryCode = key.codes[0]; + code = String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode); + } + Log.d(TAG, String.format("%s [%d] %3d,%3d %s %s", title, mPointerId, x, y, code, + isModifier() ? "modifier" : "")); + } }
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java index 6ee005510..d17bedb56 100644 --- a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java +++ b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java @@ -27,35 +27,32 @@ class ProximityKeyDetector extends KeyDetector { private int[] mDistances = new int[MAX_NEARBY_KEYS]; @Override - public int[] newCodeArray() { - int[] codes = new int[MAX_NEARBY_KEYS]; - Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY); - return codes; + protected int getMaxNearbyKeys() { + return MAX_NEARBY_KEYS; } @Override public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) { - final Key[] keys = mKeys; - if (keys == null) - throw new IllegalStateException("keyboard isn't set"); - // mKeyboard is guaranteed not null at setKeybaord() method + final Key[] keys = getKeys(); + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); int primaryIndex = LatinKeyboardBaseView.NOT_A_KEY; int closestKey = LatinKeyboardBaseView.NOT_A_KEY; int closestKeyDist = mProximityThresholdSquare + 1; int[] distances = mDistances; Arrays.fill(distances, Integer.MAX_VALUE); - int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); + int [] nearestKeyIndices = mKeyboard.getNearestKeys(touchX, touchY); final int keyCount = nearestKeyIndices.length; for (int i = 0; i < keyCount; i++) { final Key key = keys[nearestKeyIndices[i]]; int dist = 0; - boolean isInside = key.isInside(x,y); + boolean isInside = key.isInside(touchX, touchY); if (isInside) { primaryIndex = nearestKeyIndices[i]; } if (((mProximityCorrectOn - && (dist = key.squaredDistanceFrom(x, y)) < mProximityThresholdSquare) + && (dist = key.squaredDistanceFrom(touchX, touchY)) < mProximityThresholdSquare) || isInside) && key.codes[0] > 32) { // Find insertion point |