Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28de7223 authored by Xiaojun Bi's avatar Xiaojun Bi Committed by Android (Google) Code Review
Browse files

Merge "[mdfp] Refactoring Gesture Floating Preview Text Code"

parents f90fc105 d52730a2
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -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() {
+49 −0
Original line number Diff line number Diff line
/*
 * 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);
}
+179 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+16 −92
Original line number Diff line number Diff line
@@ -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<GesturePreviewTrail> 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
    }
+1 −3
Original line number Diff line number Diff line
@@ -1599,9 +1599,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);
        }
    }