From 38f55b36c3992a580cf7e20668b1eb72a4eb2431 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 20 Jul 2011 23:57:00 -0700 Subject: [PATCH] Refactor Keyboard and KeyboardView resizing and drawing code Bug: 4311428 Change-Id: Ice4050f92c8f3cec1bec2074fe6a913d04f50524 --- .../inputmethod/keyboard/KeyboardId.java | 4 +- .../keyboard/KeyboardSwitcher.java | 27 ++++-- .../inputmethod/keyboard/KeyboardView.java | 61 ++++---------- .../keyboard/LatinKeyboardBaseView.java | 2 +- .../keyboard/PopupMiniKeyboardView.java | 12 +++ .../internal/MiniKeyboardBuilder.java | 2 +- .../android/inputmethod/latin/LatinIME.java | 84 +++++++++++++++++-- 7 files changed, 129 insertions(+), 63 deletions(-) diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index b2600dd3b..a71e31ec6 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -125,10 +125,10 @@ public class KeyboardId { mEnableShiftLock); } - public KeyboardId cloneWithNewGeometry(int width) { + public KeyboardId cloneWithNewGeometry(int orientation, int width) { if (mWidth == width) return this; - return new KeyboardId(mXmlName, mXmlId, mLocale, mOrientation, width, mMode, mAttribute, + return new KeyboardId(mXmlName, mXmlId, mLocale, orientation, width, mMode, mAttribute, mHasSettingsKey, mF2KeyMode, mClobberSettingsKey, mVoiceKeyEnabled, mHasVoiceKey, mEnableShiftLock); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 37c501468..cb1e759e4 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -106,7 +106,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private int mThemeIndex = -1; private Context mThemeContext; - private int mKeyboardWidth; + private int mWindowWidth; private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); @@ -187,13 +187,24 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha setKeyboard(getKeyboard(id)); } - public void onSizeChanged() { + @SuppressWarnings("unused") + public void onSizeChanged(int w, int h, int oldw, int oldh) { final int width = mInputMethodService.getWindow().getWindow().getDecorView().getWidth(); + // If the window width hasn't fixed yet or keyboard doesn't exist, nothing to do with. if (width == 0 || mCurrentId == null) return; - mKeyboardWidth = width; - // Set keyboard with new width. - final KeyboardId newId = mCurrentId.cloneWithNewGeometry(width); + // The window width is fixed. + mWindowWidth = width; + // If this is the first time the {@link KeyboardView} has been shown, no need to reload + // keyboard. + if (oldw == 0 && oldh == 0) + return; + // Reload keyboard with new width. + final int orientation = mInputMethodService.getResources().getConfiguration().orientation; + final KeyboardId newId = mCurrentId.cloneWithNewGeometry(orientation, width); + // If the new keyboard is the same as the current one, no need to reload it. + if (newId.equals(mCurrentId)) + return; setKeyboard(getKeyboard(newId)); } @@ -289,11 +300,11 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha attribute); final Resources res = mInputMethodService.getResources(); final int orientation = res.getConfiguration().orientation; - if (mKeyboardWidth == 0) - mKeyboardWidth = res.getDisplayMetrics().widthPixels; + if (mWindowWidth == 0) + mWindowWidth = res.getDisplayMetrics().widthPixels; final Locale locale = mSubtypeSwitcher.getInputLocale(); return new KeyboardId( - res.getResourceEntryName(xmlId), xmlId, locale, orientation, mKeyboardWidth, + res.getResourceEntryName(xmlId), xmlId, locale, orientation, mWindowWidth, mode, attribute, hasSettingsKey, f2KeyMode, clobberSettingsKey, mVoiceKeyEnabled, hasVoiceKey, enableShiftLock); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index d23b8ff0e..4bda793b9 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -73,8 +73,6 @@ import java.util.HashMap; * @attr ref R.styleable#KeyboardView_shadowRadius */ public class KeyboardView extends View implements PointerTracker.DrawingProxy { - private static final boolean DEBUG_KEYBOARD_GRID = false; - // Miscellaneous constants private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable }; @@ -97,17 +95,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private ViewGroup mPreviewPlacer; // Drawing - /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/ - private boolean mDrawPending; - /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */ - private boolean mKeyboardChanged; + /** Whether the keyboard bitmap buffer needs to be redrawn before it's blitted. **/ + private boolean mBufferNeedsUpdate; /** The dirty region in the keyboard bitmap */ private final Rect mDirtyRect = new Rect(); /** The key to invalidate. */ private Key mInvalidatedKey; /** The dirty region for single key drawing */ private final Rect mInvalidatedKeyRect = new Rect(); - /** The keyboard bitmap for faster updates */ + /** The keyboard bitmap buffer for faster updates */ private Bitmap mBuffer; /** The canvas for the above mutable keyboard bitmap */ private Canvas mCanvas; @@ -361,7 +357,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mKeyboard = keyboard; LatinImeLogger.onSetKeyboard(keyboard); requestLayout(); - mKeyboardChanged = true; + mDirtyRect.set(0, 0, getWidth(), getHeight()); + mBufferNeedsUpdate = true; invalidateAllKeys(); final int keyHeight = keyboard.getRowHeight() - keyboard.getVerticalGap(); mKeyDrawParams.updateKeyHeight(keyHeight); @@ -399,25 +396,21 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } @Override - public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // Round up a little - if (mKeyboard == null) { - setMeasuredDimension( - getPaddingLeft() + getPaddingRight(), getPaddingTop() + getPaddingBottom()); + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mKeyboard != null) { + // The main keyboard expands to the display width. + final int height = mKeyboard.getKeyboardHeight() + getPaddingTop() + getPaddingBottom(); + setMeasuredDimension(widthMeasureSpec, height); } else { - int width = mKeyboard.getMinWidth() + getPaddingLeft() + getPaddingRight(); - if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) { - width = MeasureSpec.getSize(widthMeasureSpec); - } - setMeasuredDimension( - width, mKeyboard.getHeight() + getPaddingTop() + getPaddingBottom()); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); - if (mDrawPending || mBuffer == null || mKeyboardChanged) { + if (mBufferNeedsUpdate || mBuffer == null) { + mBufferNeedsUpdate = false; onBufferDraw(); } canvas.drawBitmap(mBuffer, 0, 0, null); @@ -428,14 +421,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final int height = getHeight(); if (width == 0 || height == 0) return; - if (mBuffer == null || mKeyboardChanged) { - mKeyboardChanged = false; - mDirtyRect.union(0, 0, width, height); - } if (mBuffer == null || mBuffer.getWidth() != width || mBuffer.getHeight() != height) { if (mBuffer != null) mBuffer.recycle(); mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + mDirtyRect.union(0, 0, width, height); if (mCanvas != null) { mCanvas.setBitmap(mBuffer); } else { @@ -469,24 +459,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } } - // TODO: Move this function to ProximityInfo for getting rid of - // public declarations for - // GRID_WIDTH and GRID_HEIGHT - if (DEBUG_KEYBOARD_GRID) { - Paint p = new Paint(); - p.setStyle(Paint.Style.STROKE); - p.setStrokeWidth(1.0f); - p.setColor(0x800000c0); - int cw = (mKeyboard.getMinWidth() + mKeyboard.GRID_WIDTH - 1) - / mKeyboard.GRID_WIDTH; - int ch = (mKeyboard.getHeight() + mKeyboard.GRID_HEIGHT - 1) - / mKeyboard.GRID_HEIGHT; - for (int i = 0; i <= mKeyboard.GRID_WIDTH; i++) - canvas.drawLine(i * cw, 0, i * cw, ch * mKeyboard.GRID_HEIGHT, p); - for (int i = 0; i <= mKeyboard.GRID_HEIGHT; i++) - canvas.drawLine(0, i * ch, cw * mKeyboard.GRID_WIDTH, i * ch, p); - } - // Overlay a dark rectangle to dim the keyboard if (needsToDimKeyboard()) { mPaint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); @@ -494,7 +466,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } mInvalidatedKey = null; - mDrawPending = false; mDirtyRect.setEmpty(); } @@ -864,7 +835,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { */ public void invalidateAllKeys() { mDirtyRect.union(0, 0, getWidth(), getHeight()); - mDrawPending = true; + mBufferNeedsUpdate = true; invalidate(); } @@ -884,7 +855,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final int y = key.mY + getPaddingTop(); mInvalidatedKeyRect.set(x, y, x + key.mWidth, y + key.mHeight); mDirtyRect.union(mInvalidatedKeyRect); - onBufferDraw(); + mBufferNeedsUpdate = true; invalidate(mInvalidatedKeyRect); } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java index fb57a2dba..0ad91dbb0 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java @@ -269,7 +269,7 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO: Should notify InputMethodService instead? - KeyboardSwitcher.getInstance().onSizeChanged(); + KeyboardSwitcher.getInstance().onSizeChanged(w, h, oldw, oldh); } /** diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java index 5ab44d063..a90f57c62 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java @@ -107,6 +107,18 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { setKeyPreviewPopupEnabled(false, 0); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final Keyboard keyboard = getKeyboard(); + if (keyboard != null) { + final int width = keyboard.getMinWidth() + getPaddingLeft() + getPaddingRight(); + final int height = keyboard.getKeyboardHeight() + getPaddingTop() + getPaddingBottom(); + setMeasuredDimension(width, height); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + @Override public void setKeyboard(Keyboard keyboard) { super.setKeyboard(keyboard); diff --git a/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java index cc89579bb..965c679ea 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java @@ -218,7 +218,7 @@ public class MiniKeyboardBuilder { mParams = params; keyboard.setRowHeight(params.mRowHeight); - keyboard.setHeight(params.getKeyboardHeight()); + keyboard.setKeyboardHeight(params.getKeyboardHeight()); keyboard.setMinWidth(params.getKeyboardWidth()); keyboard.setDefaultCoordX(params.getDefaultKeyCoordX() + params.mKeyWidth / 2); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 64f7e6011..c5f7dd2c7 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -173,7 +173,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private int mCorrectionMode; private int mCommittedLength; - private int mOrientation; // Keep track of the last selection range to decide if we need to show word alternatives private int mLastSelectionStart; private int mLastSelectionEnd; @@ -192,6 +191,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // TODO: Move this flag to VoiceProxy private boolean mConfigurationChanging; + // Member variables for remembering the current device orientation. + private int mDisplayOrientation; + private int mDisplayWidth; + private int mDisplayHeight; + // Object for reacting to adding/removing a dictionary pack. private BroadcastReceiver mDictionaryPackInstallReceiver = new DictionaryPackInstallBroadcastReceiver(this); @@ -199,7 +203,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Keeps track of most recently inserted text (multi-character key) for reverting private CharSequence mEnteredText; - public final UIHandler mHandler = new UIHandler(this); public static class UIHandler extends StaticInnerHandlerWrapper { @@ -211,6 +214,29 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5; private static final int MSG_SPACE_TYPED = 6; private static final int MSG_SET_BIGRAM_PREDICTIONS = 7; + private static final int MSG_CONFIRM_ORIENTATION_CHANGE = 8; + private static final int MSG_START_INPUT_VIEW = 9; + + private static class OrientationChangeArgs { + public final int mOldWidth; + public final int mOldHeight; + private int mRetryCount; + + public OrientationChangeArgs(int oldw, int oldh) { + mOldWidth = oldw; + mOldHeight = oldh; + mRetryCount = 0; + } + + public boolean hasTimedOut() { + mRetryCount++; + return mRetryCount >= 10; + } + + public boolean hasOrientationChangeFinished(DisplayMetrics dm) { + return dm.widthPixels != mOldWidth && dm.heightPixels != mOldHeight; + } + } public UIHandler(LatinIME outerInstance) { super(outerInstance); @@ -259,6 +285,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar (LatinKeyboard)msg.obj); } break; + case MSG_CONFIRM_ORIENTATION_CHANGE: { + final OrientationChangeArgs args = (OrientationChangeArgs)msg.obj; + final Resources res = latinIme.mResources; + final DisplayMetrics dm = res.getDisplayMetrics(); + if (args.hasTimedOut() || args.hasOrientationChangeFinished(dm)) { + latinIme.setDisplayGeometry(res.getConfiguration(), dm); + } else { + // It seems orientation changing is on going. + postConfirmOrientationChange(args); + } + break; + } + case MSG_START_INPUT_VIEW: + latinIme.onStartInputView((EditorInfo)msg.obj, false); + break; } } @@ -348,6 +389,33 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public boolean isAcceptingDoubleSpaces() { return hasMessages(MSG_SPACE_TYPED); } + + private void postConfirmOrientationChange(OrientationChangeArgs args) { + removeMessages(MSG_CONFIRM_ORIENTATION_CHANGE); + // Will confirm whether orientation change has finished or not after 2ms again. + sendMessageDelayed(obtainMessage(MSG_CONFIRM_ORIENTATION_CHANGE, args), 2); + } + + public void startOrientationChanging(int oldw, int oldh) { + postConfirmOrientationChange(new OrientationChangeArgs(oldw, oldh)); + } + + public boolean postStartInputView(EditorInfo attribute) { + if (hasMessages(MSG_CONFIRM_ORIENTATION_CHANGE) || hasMessages(MSG_START_INPUT_VIEW)) { + removeMessages(MSG_START_INPUT_VIEW); + // Postpone onStartInputView 20ms afterward and see if orientation change has + // finished. + sendMessageDelayed(obtainMessage(MSG_START_INPUT_VIEW, attribute), 20); + return true; + } + return false; + } + } + + private void setDisplayGeometry(Configuration conf, DisplayMetrics metric) { + mDisplayOrientation = conf.orientation; + mDisplayWidth = metric.widthPixels; + mDisplayHeight = metric.heightPixels; } @Override @@ -387,7 +455,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - mOrientation = res.getConfiguration().orientation; + setDisplayGeometry(res.getConfiguration(), res.getDisplayMetrics()); // Register to receive ringer mode change and network state change. // Also receive installation and removal of a dictionary pack. @@ -484,11 +552,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void onConfigurationChanged(Configuration conf) { mSubtypeSwitcher.onConfigurationChanged(conf); // If orientation changed while predicting, commit the change - if (conf.orientation != mOrientation) { + if (conf.orientation != mDisplayOrientation) { + mHandler.startOrientationChanging(mDisplayWidth, mDisplayHeight); InputConnection ic = getCurrentInputConnection(); commitTyped(ic); if (ic != null) ic.finishComposingText(); // For voice input - mOrientation = conf.orientation; if (isShowingOptionDialog()) mOptionsDialog.dismiss(); } @@ -525,6 +593,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void onStartInputView(EditorInfo attribute, boolean restarting) { + if (mHandler.postStartInputView(attribute)) { + return; + } + final KeyboardSwitcher switcher = mKeyboardSwitcher; LatinKeyboardView inputView = switcher.getKeyboardView(); @@ -1446,7 +1518,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public boolean isShowingSuggestionsStrip() { return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE) || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE - && mOrientation == Configuration.ORIENTATION_PORTRAIT); + && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT); } public boolean isCandidateStripVisible() {