1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.keyboard.internal;
18
19import android.content.res.TypedArray;
20import android.graphics.Canvas;
21import android.graphics.Paint;
22import android.graphics.Paint.Align;
23import android.graphics.Rect;
24import android.graphics.RectF;
25import android.text.TextUtils;
26
27import com.android.inputmethod.keyboard.PointerTracker;
28import com.android.inputmethod.latin.R;
29import com.android.inputmethod.latin.SuggestedWords;
30import com.android.inputmethod.latin.common.CoordinateUtils;
31
32import javax.annotation.Nonnull;
33
34/**
35 * The class for single gesture preview text. The class for multiple gesture preview text will be
36 * derived from it.
37 *
38 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewTextSize
39 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewTextColor
40 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewTextOffset
41 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewColor
42 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewHorizontalPadding
43 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewVerticalPadding
44 * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewRoundRadius
45 */
46public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview {
47    protected static final class GesturePreviewTextParams {
48        public final int mGesturePreviewTextOffset;
49        public final int mGesturePreviewTextHeight;
50        public final float mGesturePreviewHorizontalPadding;
51        public final float mGesturePreviewVerticalPadding;
52        public final float mGesturePreviewRoundRadius;
53        public final int mDisplayWidth;
54
55        private final int mGesturePreviewTextSize;
56        private final int mGesturePreviewTextColor;
57        private final int mGesturePreviewColor;
58        private final Paint mPaint = new Paint();
59
60        private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' };
61
62        public GesturePreviewTextParams(final TypedArray mainKeyboardViewAttr) {
63            mGesturePreviewTextSize = mainKeyboardViewAttr.getDimensionPixelSize(
64                    R.styleable.MainKeyboardView_gestureFloatingPreviewTextSize, 0);
65            mGesturePreviewTextColor = mainKeyboardViewAttr.getColor(
66                    R.styleable.MainKeyboardView_gestureFloatingPreviewTextColor, 0);
67            mGesturePreviewTextOffset = mainKeyboardViewAttr.getDimensionPixelOffset(
68                    R.styleable.MainKeyboardView_gestureFloatingPreviewTextOffset, 0);
69            mGesturePreviewColor = mainKeyboardViewAttr.getColor(
70                    R.styleable.MainKeyboardView_gestureFloatingPreviewColor, 0);
71            mGesturePreviewHorizontalPadding = mainKeyboardViewAttr.getDimension(
72                    R.styleable.MainKeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f);
73            mGesturePreviewVerticalPadding = mainKeyboardViewAttr.getDimension(
74                    R.styleable.MainKeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f);
75            mGesturePreviewRoundRadius = mainKeyboardViewAttr.getDimension(
76                    R.styleable.MainKeyboardView_gestureFloatingPreviewRoundRadius, 0.0f);
77            mDisplayWidth = mainKeyboardViewAttr.getResources().getDisplayMetrics().widthPixels;
78
79            final Paint textPaint = getTextPaint();
80            final Rect textRect = new Rect();
81            textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect);
82            mGesturePreviewTextHeight = textRect.height();
83        }
84
85        public Paint getTextPaint() {
86            mPaint.setAntiAlias(true);
87            mPaint.setTextAlign(Align.CENTER);
88            mPaint.setTextSize(mGesturePreviewTextSize);
89            mPaint.setColor(mGesturePreviewTextColor);
90            return mPaint;
91        }
92
93        public Paint getBackgroundPaint() {
94            mPaint.setColor(mGesturePreviewColor);
95            return mPaint;
96        }
97    }
98
99    private final GesturePreviewTextParams mParams;
100    private final RectF mGesturePreviewRectangle = new RectF();
101    private int mPreviewTextX;
102    private int mPreviewTextY;
103    private SuggestedWords mSuggestedWords = SuggestedWords.getEmptyInstance();
104    private final int[] mLastPointerCoords = CoordinateUtils.newInstance();
105
106    public GestureFloatingTextDrawingPreview(final TypedArray mainKeyboardViewAttr) {
107        mParams = new GesturePreviewTextParams(mainKeyboardViewAttr);
108    }
109
110    @Override
111    public void onDeallocateMemory() {
112        // Nothing to do here.
113    }
114
115    public void dismissGestureFloatingPreviewText() {
116        setSuggetedWords(SuggestedWords.getEmptyInstance());
117    }
118
119    public void setSuggetedWords(@Nonnull final SuggestedWords suggestedWords) {
120        if (!isPreviewEnabled()) {
121            return;
122        }
123        mSuggestedWords = suggestedWords;
124        updatePreviewPosition();
125    }
126
127    @Override
128    public void setPreviewPosition(final PointerTracker tracker) {
129        if (!isPreviewEnabled()) {
130            return;
131        }
132        tracker.getLastCoordinates(mLastPointerCoords);
133        updatePreviewPosition();
134    }
135
136    /**
137     * Draws gesture preview text
138     * @param canvas The canvas where preview text is drawn.
139     */
140    @Override
141    public void drawPreview(final Canvas canvas) {
142        if (!isPreviewEnabled() || mSuggestedWords.isEmpty()
143                || TextUtils.isEmpty(mSuggestedWords.getWord(0))) {
144            return;
145        }
146        final float round = mParams.mGesturePreviewRoundRadius;
147        canvas.drawRoundRect(
148                mGesturePreviewRectangle, round, round, mParams.getBackgroundPaint());
149        final String text = mSuggestedWords.getWord(0);
150        canvas.drawText(text, mPreviewTextX, mPreviewTextY, mParams.getTextPaint());
151    }
152
153    /**
154     * Updates gesture preview text position based on mLastPointerCoords.
155     */
156    protected void updatePreviewPosition() {
157        if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) {
158            invalidateDrawingView();
159            return;
160        }
161        final String text = mSuggestedWords.getWord(0);
162
163        final RectF rectangle = mGesturePreviewRectangle;
164
165        final int textHeight = mParams.mGesturePreviewTextHeight;
166        final float textWidth = mParams.getTextPaint().measureText(text);
167        final float hPad = mParams.mGesturePreviewHorizontalPadding;
168        final float vPad = mParams.mGesturePreviewVerticalPadding;
169        final float rectWidth = textWidth + hPad * 2.0f;
170        final float rectHeight = textHeight + vPad * 2.0f;
171
172        final float rectX = Math.min(
173                Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f),
174                mParams.mDisplayWidth - rectWidth);
175        final float rectY = CoordinateUtils.y(mLastPointerCoords)
176                - mParams.mGesturePreviewTextOffset - rectHeight;
177        rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight);
178
179        mPreviewTextX = (int)(rectX + hPad + textWidth / 2.0f);
180        mPreviewTextY = (int)(rectY + vPad) + textHeight;
181        // TODO: Should narrow the invalidate region.
182        invalidateDrawingView();
183    }
184}
185