From d52730a2d7a6e98245719ce5c53bcf4b3a3ba1c9 Mon Sep 17 00:00:00 2001 From: Xiaojun Bi Date: Wed, 19 Dec 2012 13:01:57 -0800 Subject: [PATCH] [mdfp] Refactoring Gesture Floating Preview Text Code This change moves gesture preview text code from PreviewPlacerView.java to separate classes. Change-Id: Id8d17eff38e714c3b06aafd0b24985a9bd2d2f52 --- .../inputmethod/keyboard/KeyboardView.java | 5 +- .../internal/AbstractDrawingPreview.java | 49 +++++ .../internal/GestureFloatingPreviewText.java | 179 ++++++++++++++++++ .../keyboard/internal/PreviewPlacerView.java | 108 ++--------- .../android/inputmethod/latin/LatinIME.java | 4 +- 5 files changed, 248 insertions(+), 97 deletions(-) create mode 100644 java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java create mode 100644 java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 61d38745e..b7bee3430 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -50,6 +50,7 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.research.ResearchLogger; @@ -870,9 +871,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, mPreviewPlacerView.dismissSlidingKeyInputPreview(); } - public void showGestureFloatingPreviewText(final String gestureFloatingPreviewText) { + public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { locatePreviewPlacerView(); - mPreviewPlacerView.setGestureFloatingPreviewText(gestureFloatingPreviewText); + mPreviewPlacerView.setGestureFloatingPreviewText(suggestedWords); } public void dismissGestureFloatingPreviewText() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java new file mode 100644 index 000000000..8a3f0645f --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 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.keyboard.internal; + +import android.graphics.Canvas; + +import com.android.inputmethod.keyboard.PointerTracker; + +/** + * Abstract base class for previews that are drawn on PreviewPlacerView, e.g., + * GestureFloatingPrevewText, GestureTrail, and SlidingKeyInputPreview. + */ +public abstract class AbstractDrawingPreview { + private boolean mPreviewEnabled; + + public void setPreviewEnabled(final boolean enabled) { + mPreviewEnabled = enabled; + } + + public boolean isPreviewEnabled() { + return mPreviewEnabled; + } + + /** + * Draws the preview + * @param canvas The canvas where the preview is drawn. + */ + public abstract void onDraw(final Canvas canvas); + + /** + * Set the position of the preview. + * @param pt The new location of the preview is based on the points in PointerTracker pt. + */ + public abstract void setPreviewPosition(final PointerTracker pt); +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java new file mode 100644 index 000000000..84cfb389c --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2012 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.keyboard.internal; + +import android.content.Context; +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.Rect; +import android.graphics.RectF; +import android.text.TextUtils; + +import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.latin.CoordinateUtils; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.ResizableIntArray; +import com.android.inputmethod.latin.SuggestedWords; + +/** + * The class for single gesture preview text. The class for multiple gesture preview text will be + * derived from it. + */ +public class GestureFloatingPreviewText extends AbstractDrawingPreview { + private static final class GesturePreviewTextParams { + public final int mGesturePreviewTextSize; + public final int mGesturePreviewTextColor; + public final int mGesturePreviewTextDimmedColor; + public final int mGesturePreviewTextOffset; + public final int mGesturePreviewTextHeight; + public final int mGesturePreviewColor; + public final float mGesturePreviewHorizontalPadding; + public final float mGesturePreviewVerticalPadding; + public final float mGesturePreviewRoundRadius; + public final Paint mTextPaint; + + private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' }; + + public GesturePreviewTextParams(final TypedArray keyboardViewAttr) { + mGesturePreviewTextSize = keyboardViewAttr.getDimensionPixelSize( + R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0); + mGesturePreviewTextColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewTextColor, 0); + mGesturePreviewTextOffset = keyboardViewAttr.getDimensionPixelOffset( + R.styleable.KeyboardView_gestureFloatingPreviewTextOffset, 0); + mGesturePreviewColor = keyboardViewAttr.getColor( + R.styleable.KeyboardView_gestureFloatingPreviewColor, 0); + mGesturePreviewHorizontalPadding = keyboardViewAttr.getDimension( + R.styleable.KeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f); + mGesturePreviewVerticalPadding = keyboardViewAttr.getDimension( + R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); + mGesturePreviewRoundRadius = keyboardViewAttr.getDimension( + R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); + mGesturePreviewTextDimmedColor = Color.GRAY; + + final Paint textPaint = new Paint(); + textPaint.setAntiAlias(true); + textPaint.setTextAlign(Align.CENTER); + textPaint.setTextSize(mGesturePreviewTextSize); + mTextPaint = textPaint; + final Rect textRect = new Rect(); + textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect); + mGesturePreviewTextHeight = textRect.height(); + } + } + + protected final GesturePreviewTextParams mParams; + protected int mPreviewWordNum; + protected final RectF mGesturePreviewRectangle = new RectF(); + protected int mHighlightedWordIndex; + + private static final int PREVIEW_TEXT_ARRAY_CAPACITY = 10; + // These variables store the positions of preview words. In multi-preview mode, the gesture + // floating preview at most shows PREVIEW_TEXT_ARRAY_CAPACITY words. + protected final ResizableIntArray mPreviewTextXArray = new ResizableIntArray( + PREVIEW_TEXT_ARRAY_CAPACITY); + protected final ResizableIntArray mPreviewTextYArray = new ResizableIntArray( + PREVIEW_TEXT_ARRAY_CAPACITY); + + protected SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; + protected final Context mContext; + public final int[] mLastPointerCoords = CoordinateUtils.newInstance(); + + public GestureFloatingPreviewText(final TypedArray typedArray, final Context context) { + mParams = new GesturePreviewTextParams(typedArray); + mHighlightedWordIndex = 0; + mContext = context; + } + + public void setSuggetedWords(final SuggestedWords suggestedWords) { + if (suggestedWords == null) { + mSuggestedWords = SuggestedWords.EMPTY; + } else { + mSuggestedWords = suggestedWords; + } + updatePreviewPosition(); + } + + protected void drawText(final Canvas canvas, final String text, final float textX, + final float textY, final int color) { + final Paint paint = mParams.mTextPaint; + paint.setColor(color); + canvas.drawText(text, textX, textY, paint); + } + + @Override + public void setPreviewPosition(final PointerTracker pt) { + pt.getLastCoordinates(mLastPointerCoords); + updatePreviewPosition(); + } + + /** + * Draws gesture preview text + * @param canvas The canvas where preview text is drawn. + */ + @Override + public void onDraw(final Canvas canvas) { + if (!isPreviewEnabled() || mSuggestedWords.isEmpty() + || TextUtils.isEmpty(mSuggestedWords.getWord(0))) { + return; + } + final Paint paint = mParams.mTextPaint; + paint.setColor(mParams.mGesturePreviewColor); + final float round = mParams.mGesturePreviewRoundRadius; + canvas.drawRoundRect(mGesturePreviewRectangle, round, round, paint); + final String text = mSuggestedWords.getWord(0); + final int textX = mPreviewTextXArray.get(0); + final int textY = mPreviewTextYArray.get(0); + drawText(canvas, text, textX, textY, mParams.mGesturePreviewTextColor); + } + + /** + * Updates gesture preview text position based on mLastPointerCoords. + */ + protected void updatePreviewPosition() { + if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) { + return; + } + final String text = mSuggestedWords.getWord(0); + + final Paint paint = mParams.mTextPaint; + final RectF rectangle = mGesturePreviewRectangle; + + final int textHeight = mParams.mGesturePreviewTextHeight; + final float textWidth = paint.measureText(text); + final float hPad = mParams.mGesturePreviewHorizontalPadding; + final float vPad = mParams.mGesturePreviewVerticalPadding; + final float rectWidth = textWidth + hPad * 2.0f; + final float rectHeight = textHeight + vPad * 2.0f; + + final int displayWidth = mContext.getResources().getDisplayMetrics().widthPixels; + final float rectX = Math.min( + Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f), + displayWidth - rectWidth); + final float rectY = CoordinateUtils.y(mLastPointerCoords) + - mParams.mGesturePreviewTextOffset - rectHeight; + rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight); + + final int textX = (int)(rectX + hPad + textWidth / 2.0f); + final int textY = (int)(rectY + vPad) + textHeight; + mPreviewTextXArray.add(0, textX); + mPreviewTextYArray.add(0, textY); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index bc734b08d..a005dc975 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -22,13 +22,10 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Paint.Align; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.graphics.RectF; import android.os.Message; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.SparseArray; import android.widget.RelativeLayout; @@ -39,15 +36,9 @@ import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.CoordinateUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.SuggestedWords; public final class PreviewPlacerView extends RelativeLayout { - private final int mGestureFloatingPreviewTextColor; - private final int mGestureFloatingPreviewTextOffset; - private final int mGestureFloatingPreviewColor; - private final float mGestureFloatingPreviewHorizontalPadding; - private final float mGestureFloatingPreviewVerticalPadding; - private final float mGestureFloatingPreviewRoundRadius; - private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance(); private final SparseArray mGesturePreviewTrails = @@ -62,16 +53,7 @@ public final class PreviewPlacerView extends RelativeLayout { private final Canvas mOffscreenCanvas = new Canvas(); private final Rect mOffscreenDirtyRect = new Rect(); private final Rect mGesturePreviewTrailBoundsRect = new Rect(); // per trail - - private final Paint mTextPaint; - private String mGestureFloatingPreviewText; - private final int mGestureFloatingPreviewTextHeight; - // {@link RectF} is needed for {@link Canvas#drawRoundRect(RectF, float, float, Paint)}. - private final RectF mGestureFloatingPreviewRectangle = new RectF(); - private final int[] mLastPointerCoords = CoordinateUtils.newInstance(); - private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' }; - private boolean mDrawsGestureFloatingPreviewText; - + private final GestureFloatingPreviewText mGestureFloatingPreviewText; private boolean mShowSlidingKeyInputPreview; private final int[] mRubberBandFrom = CoordinateUtils.newInstance(); private final int[] mRubberBandTo = CoordinateUtils.newInstance(); @@ -130,22 +112,11 @@ public final class PreviewPlacerView extends RelativeLayout { final TypedArray keyboardViewAttr = context.obtainStyledAttributes( attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - final int gestureFloatingPreviewTextSize = keyboardViewAttr.getDimensionPixelSize( - R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0); - mGestureFloatingPreviewTextColor = keyboardViewAttr.getColor( - R.styleable.KeyboardView_gestureFloatingPreviewTextColor, 0); - mGestureFloatingPreviewTextOffset = keyboardViewAttr.getDimensionPixelOffset( - R.styleable.KeyboardView_gestureFloatingPreviewTextOffset, 0); - mGestureFloatingPreviewColor = keyboardViewAttr.getColor( - R.styleable.KeyboardView_gestureFloatingPreviewColor, 0); - mGestureFloatingPreviewHorizontalPadding = keyboardViewAttr.getDimension( - R.styleable.KeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f); - mGestureFloatingPreviewVerticalPadding = keyboardViewAttr.getDimension( - R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); - mGestureFloatingPreviewRoundRadius = keyboardViewAttr.getDimension( - R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); final int gestureFloatingPreviewTextLingerTimeout = keyboardViewAttr.getInt( R.styleable.KeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); + // TODO: mGestureFloatingPreviewText could be an instance of GestureFloatingPreviewText or + // MultiGesturePreviewText, depending on the user's choice in the settings. + mGestureFloatingPreviewText = new GestureFloatingPreviewText(keyboardViewAttr, context); mGesturePreviewTrailParams = new Params(keyboardViewAttr); keyboardViewAttr.recycle(); @@ -157,15 +128,6 @@ public final class PreviewPlacerView extends RelativeLayout { gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); mGesturePaint = gesturePaint; - final Paint textPaint = new Paint(); - textPaint.setAntiAlias(true); - textPaint.setTextAlign(Align.CENTER); - textPaint.setTextSize(gestureFloatingPreviewTextSize); - mTextPaint = textPaint; - final Rect textRect = new Rect(); - textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect); - mGestureFloatingPreviewTextHeight = textRect.height(); - final Paint layerPaint = new Paint(); layerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); setLayerType(LAYER_TYPE_HARDWARE, layerPaint); @@ -181,14 +143,14 @@ public final class PreviewPlacerView extends RelativeLayout { public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail, final boolean drawsGestureFloatingPreviewText) { mDrawsGesturePreviewTrail = drawsGesturePreviewTrail; - mDrawsGestureFloatingPreviewText = drawsGestureFloatingPreviewText; + mGestureFloatingPreviewText.setPreviewEnabled(drawsGestureFloatingPreviewText); } public void invalidatePointer(final PointerTracker tracker, final boolean isOldestTracker) { final boolean needsToUpdateLastPointer = - isOldestTracker && mDrawsGestureFloatingPreviewText; + isOldestTracker && mGestureFloatingPreviewText.isPreviewEnabled(); if (needsToUpdateLastPointer) { - tracker.getLastCoordinates(mLastPointerCoords); + mGestureFloatingPreviewText.setPreviewPosition(tracker); } if (mDrawsGesturePreviewTrail) { @@ -252,6 +214,7 @@ public final class PreviewPlacerView extends RelativeLayout { super.onDraw(canvas); final int originX = CoordinateUtils.x(mKeyboardViewOrigin); final int originY = CoordinateUtils.y(mKeyboardViewOrigin); + canvas.translate(originX, originY); if (mDrawsGesturePreviewTrail) { mayAllocateOffscreenBuffer(); // Draw gesture trails to offscreen buffer. @@ -259,11 +222,10 @@ public final class PreviewPlacerView extends RelativeLayout { mOffscreenCanvas, mGesturePaint, mOffscreenDirtyRect); // Transfer offscreen buffer to screen. if (!mOffscreenDirtyRect.isEmpty()) { - final int offsetY = originY - mOffscreenOffsetY; - canvas.translate(originX, offsetY); + canvas.translate(0, - mOffscreenOffsetY); canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect, mGesturePaint); - canvas.translate(-originX, -offsetY); + canvas.translate(0, mOffscreenOffsetY); // Note: Defer clearing the dirty rectangle here because we will get cleared // rectangle on the canvas. } @@ -271,16 +233,11 @@ public final class PreviewPlacerView extends RelativeLayout { mDrawingHandler.postUpdateGestureTrailPreview(); } } - if (mDrawsGestureFloatingPreviewText) { - canvas.translate(originX, originY); - drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText); - canvas.translate(-originX, -originY); - } + mGestureFloatingPreviewText.onDraw(canvas); if (mShowSlidingKeyInputPreview) { - canvas.translate(originX, originY); drawSlidingKeyInputPreview(canvas); - canvas.translate(-originX, -originY); } + canvas.translate(-originX, -originY); } private boolean drawGestureTrails(final Canvas offscreenCanvas, final Paint paint, @@ -322,9 +279,9 @@ public final class PreviewPlacerView extends RelativeLayout { Math.min(out.bottom, bottom)); } - public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) { - if (!mDrawsGestureFloatingPreviewText) return; - mGestureFloatingPreviewText = gestureFloatingPreviewText; + public void setGestureFloatingPreviewText(final SuggestedWords suggestedWords) { + if (!mGestureFloatingPreviewText.isPreviewEnabled()) return; + mGestureFloatingPreviewText.setSuggetedWords(suggestedWords); invalidate(); } @@ -332,39 +289,6 @@ public final class PreviewPlacerView extends RelativeLayout { mDrawingHandler.dismissGestureFloatingPreviewText(); } - private void drawGestureFloatingPreviewText(final Canvas canvas, - final String gestureFloatingPreviewText) { - if (TextUtils.isEmpty(gestureFloatingPreviewText)) { - return; - } - - final Paint paint = mTextPaint; - final RectF rectangle = mGestureFloatingPreviewRectangle; - - // Paint the round rectangle background. - final int textHeight = mGestureFloatingPreviewTextHeight; - final float textWidth = paint.measureText(gestureFloatingPreviewText); - final float hPad = mGestureFloatingPreviewHorizontalPadding; - final float vPad = mGestureFloatingPreviewVerticalPadding; - final float rectWidth = textWidth + hPad * 2.0f; - final float rectHeight = textHeight + vPad * 2.0f; - final int canvasWidth = canvas.getWidth(); - final float rectX = Math.min( - Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f), - canvasWidth - rectWidth); - final float rectY = CoordinateUtils.y(mLastPointerCoords) - - mGestureFloatingPreviewTextOffset - rectHeight; - rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight); - final float round = mGestureFloatingPreviewRoundRadius; - paint.setColor(mGestureFloatingPreviewColor); - canvas.drawRoundRect(rectangle, round, round, paint); - // Paint the text preview - paint.setColor(mGestureFloatingPreviewTextColor); - final float textX = rectX + hPad + textWidth / 2.0f; - final float textY = rectY + vPad + textHeight; - canvas.drawText(gestureFloatingPreviewText, textX, textY, paint); - } - private void drawSlidingKeyInputPreview(final Canvas canvas) { // TODO: Implement rubber band preview } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index f0705a890..8196a97f8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1603,9 +1603,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (dismissGestureFloatingPreviewText) { mainKeyboardView.dismissGestureFloatingPreviewText(); } else { - final String batchInputText = suggestedWords.isEmpty() - ? null : suggestedWords.getWord(0); - mainKeyboardView.showGestureFloatingPreviewText(batchInputText); + mainKeyboardView.showGestureFloatingPreviewText(suggestedWords); } }