1/**
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17package com.android.inputmethod.dictionarypack;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.content.Context;
22import android.util.AttributeSet;
23import android.view.View;
24import android.view.ViewPropertyAnimator;
25import android.widget.Button;
26import android.widget.FrameLayout;
27
28import com.android.inputmethod.latin.R;
29
30/**
31 * A view that handles buttons inside it according to a status.
32 */
33public class ButtonSwitcher extends FrameLayout {
34    public static final int NOT_INITIALIZED = -1;
35    public static final int STATUS_NO_BUTTON = 0;
36    public static final int STATUS_INSTALL = 1;
37    public static final int STATUS_CANCEL = 2;
38    public static final int STATUS_DELETE = 3;
39    // One of the above
40    private int mStatus = NOT_INITIALIZED;
41    private int mAnimateToStatus = NOT_INITIALIZED;
42
43    // Animation directions
44    public static final int ANIMATION_IN = 1;
45    public static final int ANIMATION_OUT = 2;
46
47    private Button mInstallButton;
48    private Button mCancelButton;
49    private Button mDeleteButton;
50    private DictionaryListInterfaceState mInterfaceState;
51    private OnClickListener mOnClickListener;
52
53    public ButtonSwitcher(Context context, AttributeSet attrs) {
54        super(context, attrs);
55    }
56
57    public ButtonSwitcher(Context context, AttributeSet attrs, int defStyle) {
58        super(context, attrs, defStyle);
59    }
60
61    public void reset(final DictionaryListInterfaceState interfaceState) {
62        mStatus = NOT_INITIALIZED;
63        mAnimateToStatus = NOT_INITIALIZED;
64        mInterfaceState = interfaceState;
65    }
66
67    @Override
68    protected void onLayout(final boolean changed, final int left, final int top, final int right,
69            final int bottom) {
70        super.onLayout(changed, left, top, right, bottom);
71        mInstallButton = (Button)findViewById(R.id.dict_install_button);
72        mCancelButton = (Button)findViewById(R.id.dict_cancel_button);
73        mDeleteButton = (Button)findViewById(R.id.dict_delete_button);
74        setInternalOnClickListener(mOnClickListener);
75        setButtonPositionWithoutAnimation(mStatus);
76        if (mAnimateToStatus != NOT_INITIALIZED) {
77            // We have been asked to animate before we were ready, so we took a note of it.
78            // We are now ready: launch the animation.
79            animateButtonPosition(mStatus, mAnimateToStatus);
80            mStatus = mAnimateToStatus;
81            mAnimateToStatus = NOT_INITIALIZED;
82        }
83    }
84
85    private Button getButton(final int status) {
86        switch(status) {
87        case STATUS_INSTALL:
88            return mInstallButton;
89        case STATUS_CANCEL:
90            return mCancelButton;
91        case STATUS_DELETE:
92            return mDeleteButton;
93        default:
94            return null;
95        }
96    }
97
98    public void setStatusAndUpdateVisuals(final int status) {
99        if (mStatus == NOT_INITIALIZED) {
100            setButtonPositionWithoutAnimation(status);
101            mStatus = status;
102        } else {
103            if (null == mInstallButton) {
104                // We may come here before we have been layout. In this case we don't know our
105                // size yet so we can't start animations so we need to remember what animation to
106                // start once layout has gone through.
107                mAnimateToStatus = status;
108            } else {
109                animateButtonPosition(mStatus, status);
110                mStatus = status;
111            }
112        }
113    }
114
115    private void setButtonPositionWithoutAnimation(final int status) {
116        // This may be called by setStatus() before the layout has come yet.
117        if (null == mInstallButton) return;
118        final int width = getWidth();
119        // Set to out of the screen if that's not the currently displayed status
120        mInstallButton.setTranslationX(STATUS_INSTALL == status ? 0 : width);
121        mCancelButton.setTranslationX(STATUS_CANCEL == status ? 0 : width);
122        mDeleteButton.setTranslationX(STATUS_DELETE == status ? 0 : width);
123    }
124
125    // The helper method for {@link AnimatorListenerAdapter}.
126    void animateButtonIfStatusIsEqual(final View newButton, final int newStatus) {
127        if (newStatus != mStatus) return;
128        animateButton(newButton, ANIMATION_IN);
129    }
130
131    private void animateButtonPosition(final int oldStatus, final int newStatus) {
132        final View oldButton = getButton(oldStatus);
133        final View newButton = getButton(newStatus);
134        if (null != oldButton && null != newButton) {
135            // Transition between two buttons : animate out, then in
136            animateButton(oldButton, ANIMATION_OUT).setListener(new AnimatorListenerAdapter() {
137                @Override
138                public void onAnimationEnd(final Animator animation) {
139                    animateButtonIfStatusIsEqual(newButton, newStatus);
140                }
141            });
142        } else if (null != oldButton) {
143            animateButton(oldButton, ANIMATION_OUT);
144        } else if (null != newButton) {
145            animateButton(newButton, ANIMATION_IN);
146        }
147    }
148
149    public void setInternalOnClickListener(final OnClickListener listener) {
150        mOnClickListener = listener;
151        if (null != mInstallButton) {
152            // Already laid out : do it now
153            mInstallButton.setOnClickListener(mOnClickListener);
154            mCancelButton.setOnClickListener(mOnClickListener);
155            mDeleteButton.setOnClickListener(mOnClickListener);
156        }
157    }
158
159    private ViewPropertyAnimator animateButton(final View button, final int direction) {
160        final float outerX = getWidth();
161        final float innerX = button.getX() - button.getTranslationX();
162        mInterfaceState.removeFromCache((View)getParent());
163        if (ANIMATION_IN == direction) {
164            button.setClickable(true);
165            return button.animate().translationX(0);
166        }
167        button.setClickable(false);
168        return button.animate().translationX(outerX - innerX);
169    }
170}
171