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.animation.Animator;
20import android.animation.AnimatorInflater;
21import android.animation.AnimatorSet;
22import android.animation.ObjectAnimator;
23import android.content.res.TypedArray;
24import android.view.View;
25import android.view.animation.AccelerateInterpolator;
26import android.view.animation.DecelerateInterpolator;
27
28import com.android.inputmethod.latin.R;
29
30public final class KeyPreviewDrawParams {
31    // XML attributes of {@link MainKeyboardView}.
32    public final int mPreviewOffset;
33    public final int mPreviewHeight;
34    public final int mPreviewBackgroundResId;
35    private final int mShowUpAnimatorResId;
36    private final int mDismissAnimatorResId;
37    private boolean mHasCustomAnimationParams;
38    private int mShowUpDuration;
39    private int mDismissDuration;
40    private float mShowUpStartXScale;
41    private float mShowUpStartYScale;
42    private float mDismissEndXScale;
43    private float mDismissEndYScale;
44    private int mLingerTimeout;
45    private boolean mShowPopup = true;
46
47    // The graphical geometry of the key preview.
48    // <-width->
49    // +-------+   ^
50    // |       |   |
51    // |preview| height (visible)
52    // |       |   |
53    // +       + ^ v
54    //  \     /  |offset
55    // +-\   /-+ v
56    // |  +-+  |
57    // |parent |
58    // |    key|
59    // +-------+
60    // The background of a {@link TextView} being used for a key preview may have invisible
61    // paddings. To align the more keys keyboard panel's visible part with the visible part of
62    // the background, we need to record the width and height of key preview that don't include
63    // invisible paddings.
64    private int mVisibleWidth;
65    private int mVisibleHeight;
66    // The key preview may have an arbitrary offset and its background that may have a bottom
67    // padding. To align the more keys keyboard and the key preview we also need to record the
68    // offset between the top edge of parent key and the bottom of the visible part of key
69    // preview background.
70    private int mVisibleOffset;
71
72    public KeyPreviewDrawParams(final TypedArray mainKeyboardViewAttr) {
73        mPreviewOffset = mainKeyboardViewAttr.getDimensionPixelOffset(
74                R.styleable.MainKeyboardView_keyPreviewOffset, 0);
75        mPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize(
76                R.styleable.MainKeyboardView_keyPreviewHeight, 0);
77        mPreviewBackgroundResId = mainKeyboardViewAttr.getResourceId(
78                R.styleable.MainKeyboardView_keyPreviewBackground, 0);
79        mLingerTimeout = mainKeyboardViewAttr.getInt(
80                R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0);
81        mShowUpAnimatorResId = mainKeyboardViewAttr.getResourceId(
82                R.styleable.MainKeyboardView_keyPreviewShowUpAnimator, 0);
83        mDismissAnimatorResId = mainKeyboardViewAttr.getResourceId(
84                R.styleable.MainKeyboardView_keyPreviewDismissAnimator, 0);
85    }
86
87    public void setVisibleOffset(final int previewVisibleOffset) {
88        mVisibleOffset = previewVisibleOffset;
89    }
90
91    public int getVisibleOffset() {
92        return mVisibleOffset;
93    }
94
95    public void setGeometry(final View previewTextView) {
96        final int previewWidth = previewTextView.getMeasuredWidth();
97        final int previewHeight = mPreviewHeight;
98        // The width and height of visible part of the key preview background. The content marker
99        // of the background 9-patch have to cover the visible part of the background.
100        mVisibleWidth = previewWidth - previewTextView.getPaddingLeft()
101                - previewTextView.getPaddingRight();
102        mVisibleHeight = previewHeight - previewTextView.getPaddingTop()
103                - previewTextView.getPaddingBottom();
104        // The distance between the top edge of the parent key and the bottom of the visible part
105        // of the key preview background.
106        setVisibleOffset(mPreviewOffset - previewTextView.getPaddingBottom());
107    }
108
109    public int getVisibleWidth() {
110        return mVisibleWidth;
111    }
112
113    public int getVisibleHeight() {
114        return mVisibleHeight;
115    }
116
117    public void setPopupEnabled(final boolean enabled, final int lingerTimeout) {
118        mShowPopup = enabled;
119        mLingerTimeout = lingerTimeout;
120    }
121
122    public boolean isPopupEnabled() {
123        return mShowPopup;
124    }
125
126    public int getLingerTimeout() {
127        return mLingerTimeout;
128    }
129
130    public void setAnimationParams(final boolean hasCustomAnimationParams,
131            final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration,
132            final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) {
133        mHasCustomAnimationParams = hasCustomAnimationParams;
134        mShowUpStartXScale = showUpStartXScale;
135        mShowUpStartYScale = showUpStartYScale;
136        mShowUpDuration = showUpDuration;
137        mDismissEndXScale = dismissEndXScale;
138        mDismissEndYScale = dismissEndYScale;
139        mDismissDuration = dismissDuration;
140    }
141
142    private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f;
143    private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR =
144            new AccelerateInterpolator();
145    private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
146            new DecelerateInterpolator();
147
148    public Animator createShowUpAnimator(final View target) {
149        if (mHasCustomAnimationParams) {
150            final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(
151                    target, View.SCALE_X, mShowUpStartXScale,
152                    KEY_PREVIEW_SHOW_UP_END_SCALE);
153            final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(
154                    target, View.SCALE_Y, mShowUpStartYScale,
155                    KEY_PREVIEW_SHOW_UP_END_SCALE);
156            final AnimatorSet showUpAnimator = new AnimatorSet();
157            showUpAnimator.play(scaleXAnimator).with(scaleYAnimator);
158            showUpAnimator.setDuration(mShowUpDuration);
159            showUpAnimator.setInterpolator(DECELERATE_INTERPOLATOR);
160            return showUpAnimator;
161        }
162        final Animator animator = AnimatorInflater.loadAnimator(
163                target.getContext(), mShowUpAnimatorResId);
164        animator.setTarget(target);
165        animator.setInterpolator(DECELERATE_INTERPOLATOR);
166        return animator;
167    }
168
169    public Animator createDismissAnimator(final View target) {
170        if (mHasCustomAnimationParams) {
171            final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(
172                    target, View.SCALE_X, mDismissEndXScale);
173            final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(
174                    target, View.SCALE_Y, mDismissEndYScale);
175            final AnimatorSet dismissAnimator = new AnimatorSet();
176            dismissAnimator.play(scaleXAnimator).with(scaleYAnimator);
177            final int dismissDuration = Math.min(mDismissDuration, mLingerTimeout);
178            dismissAnimator.setDuration(dismissDuration);
179            dismissAnimator.setInterpolator(ACCELERATE_INTERPOLATOR);
180            return dismissAnimator;
181        }
182        final Animator animator = AnimatorInflater.loadAnimator(
183                target.getContext(), mDismissAnimatorResId);
184        animator.setTarget(target);
185        animator.setInterpolator(ACCELERATE_INTERPOLATOR);
186        return animator;
187    }
188}
189