1/*
2 * Copyright (C) 2014 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.Context;
20import android.graphics.Rect;
21import android.graphics.drawable.Drawable;
22import android.text.TextPaint;
23import android.text.TextUtils;
24import android.util.AttributeSet;
25import android.util.TypedValue;
26import android.view.Gravity;
27import android.widget.TextView;
28
29import com.android.inputmethod.keyboard.Key;
30import com.android.inputmethod.latin.R;
31
32import java.util.HashSet;
33
34/**
35 * The pop up key preview view.
36 */
37public class KeyPreviewView extends TextView {
38    public static final int POSITION_MIDDLE = 0;
39    public static final int POSITION_LEFT = 1;
40    public static final int POSITION_RIGHT = 2;
41
42    private final Rect mBackgroundPadding = new Rect();
43    private static final HashSet<String> sNoScaleXTextSet = new HashSet<>();
44
45    public KeyPreviewView(final Context context, final AttributeSet attrs) {
46        this(context, attrs, 0);
47    }
48
49    public KeyPreviewView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
50        super(context, attrs, defStyleAttr);
51        setGravity(Gravity.CENTER);
52    }
53
54    public void setPreviewVisual(final Key key, final KeyboardIconsSet iconsSet,
55            final KeyDrawParams drawParams) {
56        // What we show as preview should match what we show on a key top in onDraw().
57        final int iconId = key.getIconId();
58        if (iconId != KeyboardIconsSet.ICON_UNDEFINED) {
59            setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet));
60            setText(null);
61            return;
62        }
63
64        setCompoundDrawables(null, null, null, null);
65        setTextColor(drawParams.mPreviewTextColor);
66        setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams));
67        setTypeface(key.selectPreviewTypeface(drawParams));
68        // TODO Should take care of temporaryShiftLabel here.
69        setTextAndScaleX(key.getPreviewLabel());
70    }
71
72    private void setTextAndScaleX(final String text) {
73        setTextScaleX(1.0f);
74        setText(text);
75        if (sNoScaleXTextSet.contains(text)) {
76            return;
77        }
78        // TODO: Override {@link #setBackground(Drawable)} that is supported from API 16 and
79        // calculate maximum text width.
80        final Drawable background = getBackground();
81        if (background == null) {
82            return;
83        }
84        background.getPadding(mBackgroundPadding);
85        final int maxWidth = background.getIntrinsicWidth() - mBackgroundPadding.left
86                - mBackgroundPadding.right;
87        final float width = getTextWidth(text, getPaint());
88        if (width <= maxWidth) {
89            sNoScaleXTextSet.add(text);
90            return;
91        }
92        setTextScaleX(maxWidth / width);
93    }
94
95    public static void clearTextCache() {
96        sNoScaleXTextSet.clear();
97    }
98
99    private static float getTextWidth(final String text, final TextPaint paint) {
100        if (TextUtils.isEmpty(text)) {
101            return 0.0f;
102        }
103        final int len = text.length();
104        final float[] widths = new float[len];
105        final int count = paint.getTextWidths(text, 0, len, widths);
106        float width = 0;
107        for (int i = 0; i < count; i++) {
108            width += widths[i];
109        }
110        return width;
111    }
112
113    // Background state set
114    private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = {
115        { // POSITION_MIDDLE
116            {},
117            { R.attr.state_has_morekeys }
118        },
119        { // POSITION_LEFT
120            { R.attr.state_left_edge },
121            { R.attr.state_left_edge, R.attr.state_has_morekeys }
122        },
123        { // POSITION_RIGHT
124            { R.attr.state_right_edge },
125            { R.attr.state_right_edge, R.attr.state_has_morekeys }
126        }
127    };
128    private static final int STATE_NORMAL = 0;
129    private static final int STATE_HAS_MOREKEYS = 1;
130
131    public void setPreviewBackground(final boolean hasMoreKeys, final int position) {
132        final Drawable background = getBackground();
133        if (background == null) {
134            return;
135        }
136        final int hasMoreKeysState = hasMoreKeys ? STATE_HAS_MOREKEYS : STATE_NORMAL;
137        background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[position][hasMoreKeysState]);
138    }
139}
140