diff options
Diffstat (limited to 'java/src')
15 files changed, 313 insertions, 457 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java index dc7c12ba6..dd43166af 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java @@ -36,7 +36,6 @@ import com.android.inputmethod.keyboard.KeyboardView; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.Set; /** * Exposes a virtual view sub-tree for {@link KeyboardView} and generates @@ -135,9 +134,9 @@ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, info); // Add the virtual children of the root View. - // TODO(alanv): Need to assign a unique ID to each key. + // TODO: Need to assign a unique ID to each key. final Keyboard keyboard = mKeyboardView.getKeyboard(); - final Set<Key> keys = keyboard.mKeys; + final Key[] keys = keyboard.mKeys; for (Key key : keys) { final int childVirtualViewId = generateVirtualViewIdForKey(key); info.addChild(mKeyboardView, childVirtualViewId); @@ -342,8 +341,8 @@ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat mVirtualViewIdToKey.clear(); - final Set<Key> keySet = keyboard.mKeys; - for (Key key : keySet) { + final Key[] keys = keyboard.mKeys; + for (Key key : keys) { final int virtualViewId = generateVirtualViewIdForKey(key); mVirtualViewIdToKey.put(virtualViewId, key); } diff --git a/java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java b/java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java index eca922e68..9a523011a 100644 --- a/java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/MotionEventCompatUtils.java @@ -17,7 +17,7 @@ package com.android.inputmethod.compat; public class MotionEventCompatUtils { - // TODO(alanv): Remove after these are added to MotionEventCompat. + // TODO: Remove after these are added to MotionEventCompat. public static final int ACTION_HOVER_ENTER = 0x9; public static final int ACTION_HOVER_EXIT = 0xA; } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 53467122a..19795e764 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -40,12 +40,9 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard @@ -125,16 +122,17 @@ public class Keyboard { /** Maximum column for more keys keyboard */ public final int mMaxMoreKeysKeyboardColumn; - /** List of keys and icons in this keyboard */ - public final Set<Key> mKeys; - public final Set<Key> mShiftKeys; + /** Array of keys and icons in this keyboard */ + public final Key[] mKeys; + public final Key[] mShiftKeys; + public final Key[] mAltCodeKeysWhileTyping; public final KeyboardIconsSet mIconsSet; - private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); + private final HashMap<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); private final ProximityInfo mProximityInfo; - public final Map<Integer, List<Integer>> mAdditionalProximityChars; + private final Map<Integer, List<Integer>> mAdditionalProximityChars; public Keyboard(Params params) { mId = params.mId; @@ -149,12 +147,14 @@ public class Keyboard { mTopPadding = params.mTopPadding; mVerticalGap = params.mVerticalGap; - mKeys = Collections.unmodifiableSet(params.mKeys); - mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys); + mKeys = params.mKeys.toArray(new Key[params.mKeys.size()]); + mShiftKeys = params.mShiftKeys.toArray(new Key[params.mShiftKeys.size()]); + mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray( + new Key[params.mAltCodeKeysWhileTyping.size()]); mIconsSet = params.mIconsSet; mAdditionalProximityChars = params.mAdditionalProximityChars; - mProximityInfo = new ProximityInfo( + mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection, params.mAdditionalProximityChars); @@ -225,8 +225,9 @@ public class Keyboard { public int GRID_WIDTH; public int GRID_HEIGHT; - public final Set<Key> mKeys = new HashSet<Key>(); - public final Set<Key> mShiftKeys = new HashSet<Key>(); + public final ArrayList<Key> mKeys = new ArrayList<Key>(); + public final ArrayList<Key> mShiftKeys = new ArrayList<Key>(); + public final ArrayList<Key> mAltCodeKeysWhileTyping = new ArrayList<Key>(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); // TODO: Should be in Key instead of Keyboard.Params? public final Map<Integer, List<Integer>> mAdditionalProximityChars = @@ -308,6 +309,9 @@ public class Keyboard { if (key.mCode == Keyboard.CODE_SHIFT) { mShiftKeys.add(key); } + if (key.altCodeWhileTyping()) { + mAltCodeKeysWhileTyping.add(key); + } } private int mMaxHeightCount = 0; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 599adf21b..42dd6206c 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -179,15 +179,12 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions { SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources), SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); mKeyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); - // If the cached keyboard had been switched to another keyboard while the language was - // displayed on its spacebar, it might have had arbitrary text fade factor. In such - // case, we should reset the text fade factor. It is also applicable to shortcut key. - mKeyboardView.updateSpacebar(0.0f, - mSubtypeSwitcher.needsToDisplayLanguage(keyboard.mId.mLocale)); mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); - final boolean localeChanged = (oldKeyboard == null) + final boolean subtypeChanged = (oldKeyboard == null) || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); - mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged); + final boolean needsToDisplayLanguage = mSubtypeSwitcher.needsToDisplayLanguage( + keyboard.mId.mLocale); + mKeyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, needsToDisplayLanguage); } public Keyboard getKeyboard() { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index decd73d45..4c65522ec 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -44,11 +44,12 @@ import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.StringUtils; import java.util.HashMap; +import java.util.HashSet; /** * A view that renders a virtual {@link Keyboard}. * - * @attr ref R.styleable#KeyboardView_backgroundDimAmount + * @attr ref R.styleable#KeyboardView_backgroundDimAlpha * @attr ref R.styleable#KeyboardView_keyBackground * @attr ref R.styleable#KeyboardView_keyLetterRatio * @attr ref R.styleable#KeyboardView_keyLargeLetterRatio @@ -81,7 +82,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // XML attributes protected final float mVerticalCorrection; protected final int mMoreKeysLayout; - private final float mBackgroundDimAmount; + private final int mBackgroundDimAlpha; // HORIZONTAL ELLIPSIS "...", character for popup hint. private static final String POPUP_HINT_CHAR = "\u2026"; @@ -110,12 +111,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private boolean mNeedsToDimBackground; /** 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(); + /** True if all keys should be drawn */ + private boolean mInvalidateAllKeys; + /** The keys that should be drawn */ + private final HashSet<Key> mInvalidatedKeys = new HashSet<Key>(); + /** The region of invalidated keys */ + private final Rect mInvalidatedKeysRect = new Rect(); /** The keyboard bitmap buffer for faster updates */ private Bitmap mBuffer; /** The canvas for the above mutable keyboard bitmap */ @@ -335,7 +336,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { 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); + mBackgroundDimAlpha = a.getInt(R.styleable.KeyboardView_backgroundDimAlpha, 0); a.recycle(); mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; @@ -366,8 +367,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mKeyboard = keyboard; LatinImeLogger.onSetKeyboard(keyboard); requestLayout(); - mDirtyRect.set(0, 0, getWidth(), getHeight()); - mBufferNeedsUpdate = true; invalidateAllKeys(); final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; mKeyDrawParams.updateKeyHeight(keyHeight); @@ -434,47 +433,50 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (mBuffer != null) mBuffer.recycle(); mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - mDirtyRect.union(0, 0, width, height); + mInvalidateAllKeys = true; if (mCanvas != null) { mCanvas.setBitmap(mBuffer); } else { mCanvas = new Canvas(mBuffer); } } - final Canvas canvas = mCanvas; - canvas.clipRect(mDirtyRect, Op.REPLACE); - canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); if (mKeyboard == null) return; + final Canvas canvas = mCanvas; + final Paint paint = mPaint; final KeyDrawParams params = mKeyDrawParams; - if (mInvalidatedKey != null && mInvalidatedKeyRect.contains(mDirtyRect)) { - // Draw a single key. - final int keyDrawX = mInvalidatedKey.mX + mInvalidatedKey.mVisualInsetsLeft - + getPaddingLeft(); - final int keyDrawY = mInvalidatedKey.mY + getPaddingTop(); - canvas.translate(keyDrawX, keyDrawY); - onDrawKey(mInvalidatedKey, canvas, mPaint, params); - canvas.translate(-keyDrawX, -keyDrawY); - } else { + + if (mInvalidateAllKeys || mInvalidatedKeys.isEmpty()) { + mInvalidatedKeysRect.set(0, 0, getWidth(), getHeight()); + canvas.clipRect(mInvalidatedKeysRect, Op.REPLACE); + canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); // Draw all keys. for (final Key key : mKeyboard.mKeys) { - final int keyDrawX = key.mX + key.mVisualInsetsLeft + getPaddingLeft(); - final int keyDrawY = key.mY + getPaddingTop(); - canvas.translate(keyDrawX, keyDrawY); - onDrawKey(key, canvas, mPaint, params); - canvas.translate(-keyDrawX, -keyDrawY); + onDrawKey(key, canvas, paint, params); + } + } else { + // Draw invalidated keys. + for (final Key key : mInvalidatedKeys) { + final int x = key.mX + getPaddingLeft(); + final int y = key.mY + getPaddingTop(); + mInvalidatedKeysRect.set(x, y, x + key.mWidth, y + key.mHeight); + canvas.clipRect(mInvalidatedKeysRect, Op.REPLACE); + canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); + onDrawKey(key, canvas, paint, params); } } // Overlay a dark rectangle to dim the entire keyboard if (mNeedsToDimBackground) { - mPaint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); - canvas.drawRect(0, 0, width, height, mPaint); + paint.setColor(Color.BLACK); + paint.setAlpha(mBackgroundDimAlpha); + canvas.drawRect(0, 0, width, height, paint); } - mInvalidatedKey = null; - mDirtyRect.setEmpty(); + mInvalidatedKeys.clear(); + mInvalidatedKeysRect.setEmpty(); + mInvalidateAllKeys = false; } public void dimEntireKeyboard(boolean dimmed) { @@ -486,10 +488,16 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } private void onDrawKey(Key key, Canvas canvas, Paint paint, KeyDrawParams params) { + final int keyDrawX = key.mX + key.mVisualInsetsLeft + getPaddingLeft(); + final int keyDrawY = key.mY + getPaddingTop(); + canvas.translate(keyDrawX, keyDrawY); + if (!key.isSpacer()) { onDrawKeyBackground(key, canvas, params); } onDrawKeyTopVisuals(key, canvas, paint, params); + + canvas.translate(-keyDrawX, -keyDrawY); } // Draw key background. @@ -905,9 +913,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { * @see #invalidateKey(Key) */ public void invalidateAllKeys() { - mDirtyRect.union(0, 0, getWidth(), getHeight()); + mInvalidatedKeys.clear(); + mInvalidateAllKeys = true; mBufferNeedsUpdate = true; - mInvalidatedKey = null; invalidate(); } @@ -920,22 +928,21 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { */ @Override public void invalidateKey(Key key) { - if (key == null) - return; - mInvalidatedKey = key; + if (mInvalidateAllKeys) return; + if (key == null) return; + mInvalidatedKeys.add(key); final int x = key.mX + getPaddingLeft(); final int y = key.mY + getPaddingTop(); - mInvalidatedKeyRect.set(x, y, x + key.mWidth, y + key.mHeight); - mDirtyRect.union(mInvalidatedKeyRect); + mInvalidatedKeysRect.union(x, y, x + key.mWidth, y + key.mHeight); mBufferNeedsUpdate = true; - invalidate(mInvalidatedKeyRect); + invalidate(mInvalidatedKeysRect); } public void closing() { PointerTracker.dismissAllKeyPreviews(); cancelAllMessages(); - mDirtyRect.union(0, 0, getWidth(), getHeight()); + mInvalidateAllKeys = true; requestLayout(); } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 0a0307500..f4e766cb0 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -16,11 +16,11 @@ package com.android.inputmethod.keyboard; +import android.animation.ValueAnimator; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Typeface; @@ -75,9 +75,15 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private Key mSpaceKey; private Drawable mSpaceIcon; // Stuff to draw language name on spacebar. + private ValueAnimator mLanguageOnSpacebarAnimator; + private int mFinalAlphaOfLanguageOnSpacebar; + private int mDurationOfFadeoutLanguageOnSpacebar; + private static final int ALPHA_OPAQUE = 255; + private static final int LANGUAGE_ON_SPACEBAR_NEVER_DISPLAY = 0; + private static final int LANGUAGE_ON_SPACEBAR_ALWAYS_DISPLAY = -1; private boolean mNeedsToDisplayLanguage; private Locale mSpacebarLocale; - private float mSpacebarTextFadeFactor = 0.0f; + private int mSpacebarTextAlpha; private final float mSpacebarTextRatio; private float mSpacebarTextSize; private final int mSpacebarTextColor; @@ -333,6 +339,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mSpacebarTextColor = a.getColor(R.styleable.LatinKeyboardView_spacebarTextColor, 0); mSpacebarTextShadowColor = a.getColor( R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0); + mDurationOfFadeoutLanguageOnSpacebar = a.getInt( + R.styleable.LatinKeyboardView_durationOfFadeoutLanguageOnSpacebar, + LANGUAGE_ON_SPACEBAR_NEVER_DISPLAY); + final int delayBeforeFadeoutLanguageOnSpacebar = a.getInt( + R.styleable.LatinKeyboardView_delayBeforeFadeoutLangageOnSpacebar, 0); + mFinalAlphaOfLanguageOnSpacebar = a.getInt( + R.styleable.LatinKeyboardView_finalAlphaOfLanguageOnSpacebar, 0); final KeyTimerParams keyTimerParams = new KeyTimerParams(a); mPointerTrackerParams = new PointerTrackerParams(a); @@ -347,6 +360,20 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke a.recycle(); PointerTracker.setParameters(mPointerTrackerParams); + + mLanguageOnSpacebarAnimator = ValueAnimator.ofInt( + ALPHA_OPAQUE, mFinalAlphaOfLanguageOnSpacebar); + mLanguageOnSpacebarAnimator.setStartDelay(delayBeforeFadeoutLanguageOnSpacebar); + if (mDurationOfFadeoutLanguageOnSpacebar > 0) { + mLanguageOnSpacebarAnimator.setDuration(mDurationOfFadeoutLanguageOnSpacebar); + } + mLanguageOnSpacebarAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mSpacebarTextAlpha = (Integer)animation.getAnimatedValue(); + invalidateKey(mSpaceKey); + } + }); } public void setKeyboardActionListener(KeyboardActionListener listener) { @@ -722,7 +749,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke super.draw(c); tryGC = false; } catch (OutOfMemoryError e) { - tryGC = Utils.GCUtils.getInstance().tryGCOrWait("LatinKeyboardView", e); + tryGC = Utils.GCUtils.getInstance().tryGCOrWait(TAG, e); } } } @@ -762,9 +789,22 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke invalidateKey(shortcutKey); } - public void updateSpacebar(float fadeFactor, boolean needsToDisplayLanguage) { - mSpacebarTextFadeFactor = fadeFactor; + public void startDisplayLanguageOnSpacebar(boolean subtypeChanged, + boolean needsToDisplayLanguage) { + mLanguageOnSpacebarAnimator.cancel(); mNeedsToDisplayLanguage = needsToDisplayLanguage; + if (mDurationOfFadeoutLanguageOnSpacebar == LANGUAGE_ON_SPACEBAR_NEVER_DISPLAY) { + mNeedsToDisplayLanguage = false; + } else if (mDurationOfFadeoutLanguageOnSpacebar == LANGUAGE_ON_SPACEBAR_ALWAYS_DISPLAY) { + mSpacebarTextAlpha = ALPHA_OPAQUE; + } else { + if (subtypeChanged && needsToDisplayLanguage) { + mSpacebarTextAlpha = ALPHA_OPAQUE; + mLanguageOnSpacebarAnimator.start(); + } else { + mSpacebarTextAlpha = mFinalAlphaOfLanguageOnSpacebar; + } + } invalidateKey(mSpaceKey); } @@ -795,12 +835,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } } - private static int getSpacebarTextColor(int color, float fadeFactor) { - final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor), - Color.red(color), Color.green(color), Color.blue(color)); - return newColor; - } - // Compute width of text with specified text size using paint. private int getTextWidth(Paint paint, String text, float textSize) { paint.setTextSize(textSize); @@ -848,7 +882,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final int width = key.mWidth; final int height = key.mHeight; - // If application locales are explicitly selected. + // If input subtypes are explicitly selected. if (mNeedsToDisplayLanguage) { final String language = layoutLanguageOnSpacebar(paint, mSpacebarLocale, width, mSpacebarTextSize); @@ -858,9 +892,11 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final float descent = paint.descent(); final float textHeight = -paint.ascent() + descent; final float baseline = height / 2 + textHeight / 2; - paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, mSpacebarTextFadeFactor)); + paint.setColor(mSpacebarTextShadowColor); + paint.setAlpha(mSpacebarTextAlpha); canvas.drawText(language, width / 2, baseline - descent - 1, paint); - paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor)); + paint.setColor(mSpacebarTextColor); + paint.setAlpha(mSpacebarTextAlpha); canvas.drawText(language, width / 2, baseline - descent, paint); } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 7a9915be0..607b33bb4 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -25,8 +25,6 @@ import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.LatinImeLogger; import java.util.ArrayList; -import java.util.List; -import java.util.Set; public class PointerTracker { private static final String TAG = PointerTracker.class.getSimpleName(); @@ -109,7 +107,7 @@ public class PointerTracker { private static LatinKeyboardView.PointerTrackerParams sParams; private static int sTouchNoiseThresholdDistanceSquared; - private static final List<PointerTracker> sTrackers = new ArrayList<PointerTracker>(); + private static final ArrayList<PointerTracker> sTrackers = new ArrayList<PointerTracker>(); private static PointerTrackerQueue sPointerTrackerQueue; public final int mPointerId; @@ -120,7 +118,6 @@ public class PointerTracker { private KeyboardActionListener mListener = EMPTY_LISTENER; private Keyboard mKeyboard; - private Set<Key> mKeys; private int mKeyQuarterWidthSquared; private final TextView mKeyPreviewText; @@ -180,7 +177,7 @@ public class PointerTracker { } public static PointerTracker getPointerTracker(final int id, KeyEventHandler handler) { - final List<PointerTracker> trackers = sTrackers; + final ArrayList<PointerTracker> trackers = sTrackers; // Create pointer trackers until we can get 'id+1'-th tracker, if needed. for (int i = trackers.size(); i <= id; i++) { @@ -303,7 +300,6 @@ public class PointerTracker { private void setKeyDetectorInner(KeyDetector keyDetector) { mKeyDetector = keyDetector; mKeyboard = keyDetector.getKeyboard(); - mKeys = mKeyboard.mKeys; final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; } @@ -326,57 +322,76 @@ public class PointerTracker { private void setReleasedKeyGraphics(Key key) { mDrawingProxy.dismissKeyPreview(this); - if (key != null && key.isEnabled()) { - key.onReleased(); - mDrawingProxy.invalidateKey(key); - - if (key.isShift()) { - for (final Key shiftKey : mKeyboard.mShiftKeys) { - if (shiftKey != key) { - shiftKey.onReleased(); - mDrawingProxy.invalidateKey(shiftKey); - } + if (key == null || !key.isEnabled()) { + return; + } + + updateReleaseKeyGraphics(key); + + if (key.isShift()) { + for (final Key shiftKey : mKeyboard.mShiftKeys) { + if (shiftKey != key) { + updateReleaseKeyGraphics(shiftKey); } } + } - if (key.altCodeWhileTyping()) { - final Key altKey = mKeyboard.getKey(key.mAltCode); - if (altKey != null) { - altKey.onReleased(); - mDrawingProxy.invalidateKey(altKey); + if (key.altCodeWhileTyping()) { + final int altCode = key.mAltCode; + final Key altKey = mKeyboard.getKey(altCode); + if (altKey != null) { + updateReleaseKeyGraphics(altKey); + } + for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { + if (k != key && k.mAltCode == altCode) { + updateReleaseKeyGraphics(k); } } } } private void setPressedKeyGraphics(Key key) { - if (key != null && key.isEnabled()) { - if (!key.noKeyPreview()) { - mDrawingProxy.showKeyPreview(this); - } - key.onPressed(); - mDrawingProxy.invalidateKey(key); - - if (key.isShift()) { - for (final Key shiftKey : mKeyboard.mShiftKeys) { - if (shiftKey != key) { - shiftKey.onPressed(); - mDrawingProxy.invalidateKey(shiftKey); - } + if (key == null || !key.isEnabled()) { + return; + } + + if (!key.noKeyPreview()) { + mDrawingProxy.showKeyPreview(this); + } + updatePressKeyGraphics(key); + + if (key.isShift()) { + for (final Key shiftKey : mKeyboard.mShiftKeys) { + if (shiftKey != key) { + updatePressKeyGraphics(shiftKey); } } + } - if (key.altCodeWhileTyping() && mTimerProxy.isTyping()) { - final Key altKey = mKeyboard.getKey(key.mAltCode); - if (altKey != null) { - // TODO: Show altKey's preview. - altKey.onPressed(); - mDrawingProxy.invalidateKey(altKey); + if (key.altCodeWhileTyping() && mTimerProxy.isTyping()) { + final int altCode = key.mAltCode; + final Key altKey = mKeyboard.getKey(altCode); + if (altKey != null) { + updatePressKeyGraphics(altKey); + } + for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { + if (k != key && k.mAltCode == altCode) { + updatePressKeyGraphics(k); } } } } + private void updateReleaseKeyGraphics(Key key) { + key.onReleased(); + mDrawingProxy.invalidateKey(key); + } + + private void updatePressKeyGraphics(Key key) { + key.onPressed(); + mDrawingProxy.invalidateKey(key); + } + public int getLastX() { return mLastX; } @@ -691,7 +706,7 @@ public class PointerTracker { } private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, Key newKey) { - if (mKeys == null || mKeyDetector == null) + if (mKeyDetector == null) throw new NullPointerException("keyboard and/or key detector not set"); Key curKey = mCurrentKey; if (newKey == curKey) { diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 1480bba62..e2a48306a 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -17,6 +17,7 @@ package com.android.inputmethod.keyboard; import android.graphics.Rect; +import android.text.TextUtils; import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection; import com.android.inputmethod.latin.JniUtils; @@ -27,7 +28,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; public class ProximityInfo { public static final int MAX_PROXIMITY_CHARS_SIZE = 16; @@ -46,10 +46,17 @@ public class ProximityInfo { private final int mKeyboardHeight; private final int mMostCommonKeyWidth; private final Key[][] mGridNeighbors; + private final String mLocaleStr; - ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int mostCommonKeyWidth, - int mostCommonKeyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection, + ProximityInfo(String localeStr, int gridWidth, int gridHeight, int minWidth, int height, + int mostCommonKeyWidth, int mostCommonKeyHeight, final Key[] keys, + TouchPositionCorrection touchPositionCorrection, Map<Integer, List<Integer>> additionalProximityChars) { + if (TextUtils.isEmpty(localeStr)) { + mLocaleStr = ""; + } else { + mLocaleStr = localeStr; + } mGridWidth = gridWidth; mGridHeight = gridHeight; mGridSize = mGridWidth * mGridHeight; @@ -69,14 +76,14 @@ public class ProximityInfo { } public static ProximityInfo createDummyProximityInfo() { - return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key> emptySet(), - null, Collections.<Integer, List<Integer>> emptyMap()); + return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null, + Collections.<Integer, List<Integer>> emptyMap()); } public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) { final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo(); spellCheckerProximityInfo.mNativeProximityInfo = - spellCheckerProximityInfo.setProximityInfoNative( + spellCheckerProximityInfo.setProximityInfoNative("", SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 11, 3, (480 / 10), proximity, 0, null, null, null, null, null, null, null, null); return spellCheckerProximityInfo; @@ -87,7 +94,8 @@ public class ProximityInfo { JniUtils.loadNativeLibrary(); } - private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth, + private native long setProximityInfoNative( + String locale, int maxProximityCharsSize, int displayWidth, int displayHeight, int gridWidth, int gridHeight, int mostCommonKeyWidth, int[] proximityCharsArray, int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, @@ -97,8 +105,7 @@ public class ProximityInfo { private native void releaseProximityInfoNative(long nativeProximityInfo); private final void setProximityInfo(Key[][] gridNeighborKeys, int keyboardWidth, - int keyboardHeight, Set<Key> keys, - TouchPositionCorrection touchPositionCorrection) { + int keyboardHeight, final Key[] keys, TouchPositionCorrection touchPositionCorrection) { final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE); for (int i = 0; i < mGridSize; ++i) { @@ -108,7 +115,7 @@ public class ProximityInfo { gridNeighborKeys[i][j].mCode; } } - final int keyCount = keys.size(); + final int keyCount = keys.length; final int[] keyXCoordinates = new int[keyCount]; final int[] keyYCoordinates = new int[keyCount]; final int[] keyWidths = new int[keyCount]; @@ -123,8 +130,8 @@ public class ProximityInfo { sweetSpotCenterYs = new float[keyCount]; sweetSpotRadii = new float[keyCount]; calculateSweetSpotParams = true; - int i = 0; - for (final Key key : keys) { + for (int i = 0; i < keyCount; i++) { + final Key key = keys[i]; keyXCoordinates[i] = key.mX; keyYCoordinates[i] = key.mY; keyWidths[i] = key.mWidth; @@ -147,14 +154,13 @@ public class ProximityInfo { hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight); } } - i++; } } else { sweetSpotCenterXs = sweetSpotCenterYs = sweetSpotRadii = null; calculateSweetSpotParams = false; } - mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE, + mNativeProximityInfo = setProximityInfoNative(mLocaleStr, MAX_PROXIMITY_CHARS_SIZE, keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth, proximityCharsArray, keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes, @@ -177,17 +183,17 @@ public class ProximityInfo { } } - private void computeNearestNeighbors(int defaultWidth, Set<Key> keys, + private void computeNearestNeighbors(int defaultWidth, final Key[] keys, TouchPositionCorrection touchPositionCorrection, Map<Integer, List<Integer>> additionalProximityChars) { - final Map<Integer, Key> keyCodeMap = new HashMap<Integer, Key>(); + final HashMap<Integer, Key> keyCodeMap = new HashMap<Integer, Key>(); for (final Key key : keys) { keyCodeMap.put(key.mCode, key); } final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE); final int threshold = thresholdBase * thresholdBase; // Round-up so we don't have any pixels outside the grid - final Key[] neighborKeys = new Key[keys.size()]; + final Key[] neighborKeys = new Key[keys.length]; final int gridWidth = mGridWidth * mCellWidth; final int gridHeight = mGridHeight * mCellHeight; for (int x = 0; x < gridWidth; x += mCellWidth) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index ca711ec7d..9b9c86179 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -24,7 +24,6 @@ import android.util.Log; import com.android.inputmethod.latin.R; import java.util.HashMap; -import java.util.Map; public class KeyboardIconsSet { private static final String TAG = KeyboardIconsSet.class.getSimpleName(); @@ -35,8 +34,9 @@ public class KeyboardIconsSet { private final Drawable[] mIcons = new Drawable[NUM_ICONS + 1]; - private static final Map<Integer, Integer> ATTR_ID_TO_ICON_ID = new HashMap<Integer, Integer>(); - private static final Map<String, Integer> NAME_TO_ICON_ID = new HashMap<String, Integer>(); + private static final HashMap<Integer, Integer> ATTR_ID_TO_ICON_ID + = new HashMap<Integer, Integer>(); + private static final HashMap<String, Integer> NAME_TO_ICON_ID = new HashMap<String, Integer>(); private static final String[] ICON_NAMES = new String[NUM_ICONS + 1]; private static final int ATTR_UNDEFINED = 0; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d96b858eb..f41972e8b 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -72,6 +72,7 @@ import com.android.inputmethod.latin.suggestions.SuggestionsView; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -241,18 +242,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { private static final int MSG_UPDATE_SHIFT_STATE = 1; private static final int MSG_VOICE_RESULTS = 2; - private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 3; - private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 4; - private static final int MSG_SPACE_TYPED = 5; - private static final int MSG_SET_BIGRAM_PREDICTIONS = 6; - private static final int MSG_PENDING_IMS_CALLBACK = 7; - private static final int MSG_UPDATE_SUGGESTIONS = 8; - - private int mDelayBeforeFadeoutLanguageOnSpacebar; + private static final int MSG_SPACE_TYPED = 4; + private static final int MSG_SET_BIGRAM_PREDICTIONS = 5; + private static final int MSG_PENDING_IMS_CALLBACK = 6; + private static final int MSG_UPDATE_SUGGESTIONS = 7; + private int mDelayUpdateSuggestions; private int mDelayUpdateShiftState; - private int mDurationOfFadeoutLanguageOnSpacebar; - private float mFinalFadeoutFactorOfLanguageOnSpacebar; private long mDoubleSpacesTurnIntoPeriodTimeout; public UIHandler(LatinIME outerInstance) { @@ -261,16 +257,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void onCreate() { final Resources res = getOuterInstance().getResources(); - mDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger( - R.integer.config_delay_before_fadeout_language_on_spacebar); mDelayUpdateSuggestions = res.getInteger(R.integer.config_delay_update_suggestions); mDelayUpdateShiftState = res.getInteger(R.integer.config_delay_update_shift_state); - mDurationOfFadeoutLanguageOnSpacebar = res.getInteger( - R.integer.config_duration_of_fadeout_language_on_spacebar); - mFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger( - R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f; mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger( R.integer.config_double_spaces_turn_into_period_timeout); } @@ -279,7 +269,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void handleMessage(Message msg) { final LatinIME latinIme = getOuterInstance(); final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; - final LatinKeyboardView inputView = switcher.getKeyboardView(); switch (msg.what) { case MSG_UPDATE_SUGGESTIONS: latinIme.updateSuggestions(); @@ -295,17 +284,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization() || (keyboard != null && keyboard.isShiftedOrShiftLocked())); break; - case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR: - setSpacebarTextFadeFactor(inputView, - (1.0f + mFinalFadeoutFactorOfLanguageOnSpacebar) / 2, - (Keyboard)msg.obj); - sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj), - mDurationOfFadeoutLanguageOnSpacebar); - break; - case MSG_DISMISS_LANGUAGE_ON_SPACEBAR: - setSpacebarTextFadeFactor(inputView, mFinalFadeoutFactorOfLanguageOnSpacebar, - (Keyboard)msg.obj); - break; } } @@ -344,41 +322,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar sendMessage(obtainMessage(MSG_VOICE_RESULTS)); } - private static void setSpacebarTextFadeFactor(LatinKeyboardView inputView, - float fadeFactor, Keyboard oldKeyboard) { - if (inputView == null) return; - final Keyboard keyboard = inputView.getKeyboard(); - if (keyboard == oldKeyboard) { - inputView.updateSpacebar(fadeFactor, - SubtypeSwitcher.getInstance().needsToDisplayLanguage( - keyboard.mId.mLocale)); - } - } - - public void startDisplayLanguageOnSpacebar(boolean localeChanged) { - final LatinIME latinIme = getOuterInstance(); - removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR); - removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR); - final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView(); - if (inputView != null) { - final Keyboard keyboard = latinIme.mKeyboardSwitcher.getKeyboard(); - // The language is always displayed when the delay is negative. - final boolean needsToDisplayLanguage = localeChanged - || mDelayBeforeFadeoutLanguageOnSpacebar < 0; - // The language is never displayed when the delay is zero. - if (mDelayBeforeFadeoutLanguageOnSpacebar != 0) { - setSpacebarTextFadeFactor(inputView, - needsToDisplayLanguage ? 1.0f : mFinalFadeoutFactorOfLanguageOnSpacebar, - keyboard); - } - // The fadeout animation will start when the delay is positive. - if (localeChanged && mDelayBeforeFadeoutLanguageOnSpacebar > 0) { - sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard), - mDelayBeforeFadeoutLanguageOnSpacebar); - } - } - } - public void startDoubleSpacesTimer() { removeMessages(MSG_SPACE_TYPED); sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout); @@ -980,13 +923,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } - final List<CharSequence> applicationSuggestedWords = + final List<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = SuggestedWords.Builder.getFromApplicationSpecifiedCompletions( applicationSpecifiedCompletions); - SuggestedWords.Builder builder = new SuggestedWords.Builder() - .addWords(applicationSuggestedWords, null) - .setTypedWordValid(false) - .setHasMinimalSuggestion(false); + SuggestedWords.Builder builder = new SuggestedWords.Builder(applicationSuggestedWords, + false /* typedWordValid */, + false /* hasMinimalSuggestion */, + false /* allowsToBeAutoCorrected */, + false /* isPunctuationSuggestions */); // When in fullscreen mode, show completions generated by the application final SuggestedWords words = builder.build(); final boolean isAutoCorrection = false; @@ -1840,8 +1784,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (previousSuggestions == mSettingsValues.mSuggestPuncList) { previousSuggestions = SuggestedWords.EMPTY; } - final SuggestedWords.Builder obsoleteSuggestionsBuilder = new SuggestedWords.Builder() - .addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); + final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = + SuggestedWords.Builder.getTypedWordAndPreviousSuggestions( + typedWord, previousSuggestions); + final SuggestedWords.Builder obsoleteSuggestionsBuilder = + new SuggestedWords.Builder(typedWordAndPreviousSuggestions, + false /* typedWordValid */, + false /* hasMinimalSuggestion */, + false /* allowsToBeAutoCorrected */, + false /* isPunctuationSuggestions */); showSuggestions(obsoleteSuggestionsBuilder.build(), typedWord); } } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index abd1dc692..0a4aea140 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -28,6 +28,7 @@ import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.keyboard.internal.KeySpecParser; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -174,28 +175,42 @@ public class SettingsValues { } private static SuggestedWords createSuggestPuncList(final String[] puncs) { - final SuggestedWords.Builder builder = new SuggestedWords.Builder(); + final ArrayList<SuggestedWords.SuggestedWordInfo> puncList = + new ArrayList<SuggestedWords.SuggestedWordInfo>(); if (puncs != null) { for (final String puncSpec : puncs) { - builder.addWord(KeySpecParser.getLabel(puncSpec)); + puncList.add(new SuggestedWords.SuggestedWordInfo( + KeySpecParser.getLabel(puncSpec))); } } - return builder.setIsPunctuationSuggestions().build(); + final SuggestedWords.Builder builder = new SuggestedWords.Builder(puncList, + false /* typedWordValid */, + false /* hasMinimalSuggestion */, + false /* allowsToBeAutoCorrected */, + true /* isPunctuationSuggestions */); + return builder.build(); } private static SuggestedWords createSuggestPuncOutputTextList(final String[] puncs) { - final SuggestedWords.Builder builder = new SuggestedWords.Builder(); + final ArrayList<SuggestedWords.SuggestedWordInfo> puncOutputTextList = + new ArrayList<SuggestedWords.SuggestedWordInfo>(); if (puncs != null) { for (final String puncSpec : puncs) { final String outputText = KeySpecParser.getOutputText(puncSpec); if (outputText != null) { - builder.addWord(outputText); + puncOutputTextList.add(new SuggestedWords.SuggestedWordInfo(outputText)); } else { - builder.addWord(KeySpecParser.getLabel(puncSpec)); + puncOutputTextList.add(new SuggestedWords.SuggestedWordInfo( + KeySpecParser.getLabel(puncSpec))); } } } - return builder.setIsPunctuationSuggestions().build(); + final SuggestedWords.Builder builder = new SuggestedWords.Builder(puncOutputTextList, + false /* typedWordValid */, + false /* hasMinimalSuggestion */, + false /* allowsToBeAutoCorrected */, + true /* isPunctuationSuggestions */); + return builder.build(); } private static String createWordSeparators(final String weakSpaceStrippers, diff --git a/java/src/com/android/inputmethod/latin/StringBuilderPool.java b/java/src/com/android/inputmethod/latin/StringBuilderPool.java deleted file mode 100644 index a663ed43e..000000000 --- a/java/src/com/android/inputmethod/latin/StringBuilderPool.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A pool of string builders to be used from anywhere. - */ -public class StringBuilderPool { - // Singleton - private static final StringBuilderPool sInstance = new StringBuilderPool(); - private static final boolean DEBUG = false; - private StringBuilderPool() {} - // TODO: Make this a normal array with a size of 20, or a ConcurrentQueue - private final List<StringBuilder> mPool = - Collections.synchronizedList(new ArrayList<StringBuilder>()); - - public static StringBuilder getStringBuilder(final int initialSize) { - // TODO: although the pool is synchronized, the following is not thread-safe. - // Two threads entering this at the same time could take the same size of the pool and the - // second to attempt removing this index from the pool would crash with an - // IndexOutOfBoundsException. - // At the moment this pool is only used in Suggest.java and only in one thread so it's - // okay. The simplest thing to do here is probably to replace the ArrayList with a - // ConcurrentQueue. - final int poolSize = sInstance.mPool.size(); - final StringBuilder sb = poolSize > 0 ? (StringBuilder) sInstance.mPool.remove(poolSize - 1) - : new StringBuilder(initialSize); - sb.setLength(0); - return sb; - } - - public static void recycle(final StringBuilder garbage) { - if (DEBUG) { - final int gid = garbage.hashCode(); - for (final StringBuilder q : sInstance.mPool) { - if (gid == q.hashCode()) throw new RuntimeException("Duplicate id " + gid); - } - } - sInstance.mPool.add(garbage); - } - - public static void ensureCapacity(final int capacity, final int initialSize) { - for (int i = sInstance.mPool.size(); i < capacity; ++i) { - final StringBuilder sb = new StringBuilder(initialSize); - sInstance.mPool.add(sb); - } - } - - public static int getSize() { - return sInstance.mPool.size(); - } -} diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 81c3b4edf..7b34cae63 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -142,7 +142,7 @@ public class StringUtils { for (int j = 0; j < i; j++) { CharSequence previous = suggestions.get(j); if (TextUtils.equals(cur, previous)) { - removeFromSuggestions(suggestions, i); + suggestions.remove(i); i--; break; } @@ -151,14 +151,6 @@ public class StringUtils { } } - private static void removeFromSuggestions(final ArrayList<CharSequence> suggestions, - final int index) { - final CharSequence garbage = suggestions.remove(index); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - } - } - public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { if (returnsNameInThisLocale) { return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index f17c1d95a..28d3b4437 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -98,7 +98,7 @@ public class Suggest implements Dictionary.WordCallback { private int[] mBigramScores = new int[PREF_MAX_BIGRAMS]; private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>(); - ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>(); + private ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>(); private CharSequence mConsideredWord; // TODO: Remove these member variables by passing more context to addWord() callback method @@ -122,7 +122,6 @@ public class Suggest implements Dictionary.WordCallback { private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) { mWhiteListDictionary = new WhitelistDictionary(context, locale); addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_WHITELIST, mWhiteListDictionary); - StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength()); } private void initAsynchronously(final Context context, final int dictionaryResId, @@ -181,7 +180,7 @@ public class Suggest implements Dictionary.WordCallback { return mUnigramDictionaries; } - public int getApproxMaxWordLength() { + public static int getApproxMaxWordLength() { return APPROX_MAX_WORD_LENGTH; } @@ -216,27 +215,11 @@ public class Suggest implements Dictionary.WordCallback { mAutoCorrectionThreshold = threshold; } - /** - * Number of suggestions to generate from the input key sequence. This has - * to be a number between 1 and 100 (inclusive). - * @param maxSuggestions - * @throws IllegalArgumentException if the number is out of range - */ - public void setMaxSuggestions(int maxSuggestions) { - if (maxSuggestions < 1 || maxSuggestions > 100) { - throw new IllegalArgumentException("maxSuggestions must be between 1 and 100"); - } - mPrefMaxSuggestions = maxSuggestions; - mScores = new int[mPrefMaxSuggestions]; - mBigramScores = new int[PREF_MAX_BIGRAMS]; - collectGarbage(mSuggestions, mPrefMaxSuggestions); - StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength()); - } - - private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) { + private static CharSequence capitalizeWord(final boolean all, final boolean first, + final CharSequence word) { if (TextUtils.isEmpty(word) || !(all || first)) return word; final int wordLength = word.length(); - final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength()); + final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); // TODO: Must pay attention to locale when changing case. if (all) { sb.append(word.toString().toUpperCase()); @@ -250,12 +233,7 @@ public class Suggest implements Dictionary.WordCallback { } protected void addBigramToSuggestions(CharSequence bigram) { - // TODO: Try to be a little more shrewd with resource allocation. - // At the moment we copy this object because the StringBuilders are pooled (see - // StringBuilderPool.java) and when we are finished using mSuggestions and - // mBigramSuggestions we will take everything from both and insert them back in the - // pool, so we can't allow the same object to be in both lists at the same time. - final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength()); + final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); sb.append(bigram); mSuggestions.add(sb); } @@ -266,7 +244,7 @@ public class Suggest implements Dictionary.WordCallback { mIsFirstCharCapitalized = false; mIsAllUpperCase = false; mTrailingSingleQuotesCount = 0; - collectGarbage(mSuggestions, mPrefMaxSuggestions); + mSuggestions = new ArrayList<CharSequence>(mPrefMaxSuggestions); Arrays.fill(mScores, 0); // Treating USER_TYPED as UNIGRAM suggestion for logging now. @@ -274,7 +252,7 @@ public class Suggest implements Dictionary.WordCallback { mConsideredWord = ""; Arrays.fill(mBigramScores, 0); - collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS); + mBigramSuggestions = new ArrayList<CharSequence>(PREF_MAX_BIGRAMS); CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) { @@ -291,9 +269,12 @@ public class Suggest implements Dictionary.WordCallback { StringUtils.removeDupes(mSuggestions); - return new SuggestedWords.Builder().addWords(mSuggestions, null) - .setAllowsToBeAutoCorrected(false) - .setHasAutoCorrection(false); + return new SuggestedWords.Builder( + SuggestedWords.Builder.getFromCharSequenceList(mSuggestions), + false /* typedWordValid */, + false /* hasMinimalSuggestion */, + false /* allowsToBeAutoCorrected */, + false /* isPunctuationSuggestions */); } // TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder @@ -304,7 +285,7 @@ public class Suggest implements Dictionary.WordCallback { mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsAllUpperCase = wordComposer.isAllUpperCase(); mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); - collectGarbage(mSuggestions, mPrefMaxSuggestions); + mSuggestions = new ArrayList<CharSequence>(mPrefMaxSuggestions); Arrays.fill(mScores, 0); final String typedWord = wordComposer.getTypedWord(); @@ -327,7 +308,7 @@ public class Suggest implements Dictionary.WordCallback { if (wordComposer.size() <= 1 && (correctionMode == CORRECTION_FULL_BIGRAM)) { // At first character typed, search only the bigrams Arrays.fill(mBigramScores, 0); - collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS); + mBigramSuggestions = new ArrayList<CharSequence>(PREF_MAX_BIGRAMS); if (!TextUtils.isEmpty(prevWordForBigram)) { CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); @@ -412,6 +393,7 @@ public class Suggest implements Dictionary.WordCallback { StringUtils.removeDupes(mSuggestions); final SuggestedWords.Builder builder; + final ArrayList<SuggestedWords.SuggestedWordInfo> scoreInfoList; if (DBG) { // TODO: this doesn't take into account the fact that removing dupes from mSuggestions // may have made mScores[] and mSuggestions out of sync. @@ -420,8 +402,7 @@ public class Suggest implements Dictionary.WordCallback { double normalizedScore = BinaryDictionary.calcNormalizedScore( typedWord, autoCorrectionSuggestion.toString(), autoCorrectionSuggestionScore); - ArrayList<SuggestedWords.SuggestedWordInfo> scoreInfoList = - new ArrayList<SuggestedWords.SuggestedWordInfo>(); + scoreInfoList = new ArrayList<SuggestedWords.SuggestedWordInfo>(); scoreInfoList.add(new SuggestedWords.SuggestedWordInfo(autoCorrectionSuggestion, "+", false)); final int suggestionsSize = mSuggestions.size(); @@ -445,13 +426,8 @@ public class Suggest implements Dictionary.WordCallback { scoreInfoList.add(new SuggestedWords.SuggestedWordInfo(mSuggestions.get(i), "--", false)); } - builder = new SuggestedWords.Builder().addWords(mSuggestions, scoreInfoList) - .setAllowsToBeAutoCorrected(allowsToBeAutoCorrected) - .setHasAutoCorrection(hasAutoCorrection); } else { - builder = new SuggestedWords.Builder().addWords(mSuggestions, null) - .setAllowsToBeAutoCorrected(allowsToBeAutoCorrected) - .setHasAutoCorrection(hasAutoCorrection); + scoreInfoList = SuggestedWords.Builder.getFromCharSequenceList(mSuggestions); } boolean autoCorrectionAvailable = hasAutoCorrection; @@ -461,8 +437,11 @@ public class Suggest implements Dictionary.WordCallback { } // Don't auto-correct words with multiple capital letter autoCorrectionAvailable &= !wordComposer.isMostlyCaps(); - builder.setTypedWordValid(!allowsToBeAutoCorrected).setHasMinimalSuggestion( - autoCorrectionAvailable); + builder = new SuggestedWords.Builder(scoreInfoList, + !allowsToBeAutoCorrected /* typedWordValid */, + autoCorrectionAvailable /* hasMinimalSuggestion */, + allowsToBeAutoCorrected /* allowsToBeAutoCorrected */, + false /* isPunctuationSuggestions */); if (allowsToBeAutoCorrected && builder.size() > 1 && mAutoCorrectionThreshold > 0 && Suggest.shouldBlockAutoCorrectionBySafetyNet(typedWord, builder.getWord(1))) { builder.setShouldBlockAutoCorrectionBySafetyNet(); @@ -540,7 +519,7 @@ public class Suggest implements Dictionary.WordCallback { System.arraycopy(sortedScores, pos, sortedScores, pos + 1, prefMaxSuggestions - pos - 1); sortedScores[pos] = score; - final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength()); + final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); // TODO: Must pay attention to locale when changing case. if (mIsAllUpperCase) { sb.append(new String(word, offset, length).toUpperCase()); @@ -557,10 +536,7 @@ public class Suggest implements Dictionary.WordCallback { } suggestions.add(pos, sb); if (suggestions.size() > prefMaxSuggestions) { - final CharSequence garbage = suggestions.remove(prefMaxSuggestions); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - } + suggestions.remove(prefMaxSuggestions); } else { LatinImeLogger.onAddSuggestedWord(sb.toString(), dicTypeId, dataTypeForLog); } @@ -571,40 +547,22 @@ public class Suggest implements Dictionary.WordCallback { // TODO This is almost O(n^2). Might need fix. // search whether the word appeared in bigram data int bigramSuggestSize = mBigramSuggestions.size(); - for(int i = 0; i < bigramSuggestSize; i++) { - if(mBigramSuggestions.get(i).length() == length) { + for (int i = 0; i < bigramSuggestSize; i++) { + if (mBigramSuggestions.get(i).length() == length) { boolean chk = true; - for(int j = 0; j < length; j++) { - if(mBigramSuggestions.get(i).charAt(j) != word[offset+j]) { + for (int j = 0; j < length; j++) { + if (mBigramSuggestions.get(i).charAt(j) != word[offset+j]) { chk = false; break; } } - if(chk) return i; + if (chk) return i; } } return -1; } - private static void collectGarbage(ArrayList<CharSequence> suggestions, - int prefMaxSuggestions) { - int poolSize = StringBuilderPool.getSize(); - int garbageSize = suggestions.size(); - while (poolSize < prefMaxSuggestions && garbageSize > 0) { - final CharSequence garbage = suggestions.get(garbageSize - 1); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - poolSize++; - } - garbageSize--; - } - if (poolSize == prefMaxSuggestions + 1) { - Log.w("Suggest", "String pool got too big: " + poolSize); - } - suggestions.clear(); - } - public void close() { final Set<Dictionary> dictionaries = new HashSet<Dictionary>(); dictionaries.addAll(mUnigramDictionaries.values()); diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 4a51e796d..144e67482 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin; -import android.text.TextUtils; import android.view.inputmethod.CompletionInfo; import java.util.ArrayList; @@ -74,115 +73,66 @@ public class SuggestedWords { } public static class Builder { - private boolean mTypedWordValid; - private boolean mHasMinimalSuggestion; - private boolean mIsPunctuationSuggestions; + private final boolean mTypedWordValid; + private final boolean mHasMinimalSuggestion; + private final boolean mIsPunctuationSuggestions; private boolean mShouldBlockAutoCorrectionBySafetyNet; - private boolean mAllowsToBeAutoCorrected; - private boolean mHasAutoCorrection; - private List<SuggestedWordInfo> mSuggestedWordInfoList = - new ArrayList<SuggestedWordInfo>(); - - public Builder() { - // Nothing to do here. - } - - public Builder addWords(List<CharSequence> words, - List<SuggestedWordInfo> suggestedWordInfoList) { - final int N = words.size(); - for (int i = 0; i < N; ++i) { - final CharSequence word = words.get(i); - SuggestedWordInfo suggestedWordInfo = null; - if (suggestedWordInfoList != null) { - suggestedWordInfo = suggestedWordInfoList.get(i); - } - if (suggestedWordInfo == null) { - suggestedWordInfo = new SuggestedWordInfo(word); - } - addWord(word, suggestedWordInfo); - } - return this; - } - - public Builder addWord(CharSequence word) { - return addWord(word, null, false); - } - - public Builder addWord(CharSequence word, CharSequence debugString, - boolean isPreviousSuggestedWord) { - SuggestedWordInfo info = new SuggestedWordInfo(word, debugString, - isPreviousSuggestedWord); - return addWord(word, info); + private final boolean mAllowsToBeAutoCorrected; + private final List<SuggestedWordInfo> mSuggestedWordInfoList; + + public Builder(final List<SuggestedWordInfo> suggestedWordInfoList, + final boolean typedWordValid, + final boolean hasMinimalSuggestion, + final boolean allowsToBeAutoCorrected, + final boolean isPunctuationSuggestions) { + mSuggestedWordInfoList = suggestedWordInfoList; + mTypedWordValid = typedWordValid; + mHasMinimalSuggestion = hasMinimalSuggestion; + mAllowsToBeAutoCorrected = allowsToBeAutoCorrected; + mIsPunctuationSuggestions = isPunctuationSuggestions; } - /* package for tests */ - Builder addWord(CharSequence word, SuggestedWordInfo suggestedWordInfo) { - if (!TextUtils.isEmpty(suggestedWordInfo.mWord)) { - // It's okay if suggestedWordInfo is null since it's checked where it's used. - mSuggestedWordInfoList.add(suggestedWordInfo); + public static ArrayList<SuggestedWordInfo> getFromCharSequenceList( + final List<CharSequence> wordList) { + final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>(); + for (CharSequence word : wordList) { + if (null != word) result.add(new SuggestedWordInfo(word, null, false)); } - return this; + return result; } - public static List<CharSequence> getFromApplicationSpecifiedCompletions( + public static List<SuggestedWordInfo> getFromApplicationSpecifiedCompletions( final CompletionInfo[] infos) { - final ArrayList<CharSequence> result = new ArrayList<CharSequence>(); + final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>(); for (CompletionInfo info : infos) { - if (null != info) result.add(info.getText()); + if (null != info) result.add(new SuggestedWordInfo(info.getText(), null, false)); } return result; } - public Builder setTypedWordValid(boolean typedWordValid) { - mTypedWordValid = typedWordValid; - return this; - } - - public Builder setHasMinimalSuggestion(boolean hasMinimalSuggestion) { - mHasMinimalSuggestion = hasMinimalSuggestion; - return this; - } - - public Builder setIsPunctuationSuggestions() { - mIsPunctuationSuggestions = true; - return this; - } - public Builder setShouldBlockAutoCorrectionBySafetyNet() { mShouldBlockAutoCorrectionBySafetyNet = true; return this; } - public Builder setAllowsToBeAutoCorrected(final boolean allowsToBeAutoCorrected) { - mAllowsToBeAutoCorrected = allowsToBeAutoCorrected; - return this; - } - - public Builder setHasAutoCorrection(final boolean hasAutoCorrection) { - mHasAutoCorrection = hasAutoCorrection; - return this; - } - // Should get rid of the first one (what the user typed previously) from suggestions // and replace it with what the user currently typed. - public Builder addTypedWordAndPreviousSuggestions(CharSequence typedWord, - SuggestedWords previousSuggestions) { - mSuggestedWordInfoList.clear(); + public static ArrayList<SuggestedWordInfo> getTypedWordAndPreviousSuggestions( + final CharSequence typedWord, final SuggestedWords previousSuggestions) { + final ArrayList<SuggestedWordInfo> suggestionsList = new ArrayList<SuggestedWordInfo>(); final HashSet<String> alreadySeen = new HashSet<String>(); - addWord(typedWord, null, false); + suggestionsList.add(new SuggestedWordInfo(typedWord, null, false)); alreadySeen.add(typedWord.toString()); final int previousSize = previousSuggestions.size(); for (int pos = 1; pos < previousSize; pos++) { final String prevWord = previousSuggestions.getWord(pos).toString(); // Filter out duplicate suggestion. if (!alreadySeen.contains(prevWord)) { - addWord(prevWord, null, true); + suggestionsList.add(new SuggestedWordInfo(prevWord, null, true)); alreadySeen.add(prevWord); } } - mTypedWordValid = false; - mHasMinimalSuggestion = false; - return this; + return suggestionsList; } public SuggestedWords build() { @@ -203,10 +153,6 @@ public class SuggestedWords { return mAllowsToBeAutoCorrected; } - public boolean hasAutoCorrection() { - return mHasAutoCorrection; - } - @Override public String toString() { // Pretty-print method to help debug |