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.deskclock.widget;
18
19import android.animation.Animator;
20import android.animation.AnimatorInflater;
21import android.animation.AnimatorListenerAdapter;
22import android.content.Context;
23import android.util.AttributeSet;
24import android.view.LayoutInflater;
25import android.view.MotionEvent;
26import android.view.View;
27import android.widget.FrameLayout;
28import android.widget.ImageView;
29import android.widget.LinearLayout;
30import android.widget.TextView;
31
32import com.android.deskclock.R;
33
34/**
35 * A custom {@link View} that exposes an action to the user.
36 * <p>
37 * This is a copy of packages/apps/UnifiedEmail/src/com/android/mail/ui/ActionableToastBar.java
38 * with minor modifications.
39 */
40public class ActionableToastBar extends LinearLayout {
41    private boolean mHidden = false;
42    private Animator mShowAnimation;
43    private Animator mHideAnimation;
44    private final int mBottomMarginSizeInConversation;
45
46    /** Icon for the description. */
47    private ImageView mActionDescriptionIcon;
48    /** The clickable view */
49    private View mActionButton;
50    /** Icon for the action button. */
51    private View mActionIcon;
52    /** The view that contains the description. */
53    private TextView mActionDescriptionView;
54    /** The view that contains the text for the action button. */
55    private TextView mActionText;
56    //private ToastBarOperation mOperation;
57
58    public ActionableToastBar(Context context) {
59        this(context, null);
60    }
61
62    public ActionableToastBar(Context context, AttributeSet attrs) {
63        this(context, attrs, 0);
64    }
65
66    public ActionableToastBar(Context context, AttributeSet attrs, int defStyle) {
67        super(context, attrs, defStyle);
68        mBottomMarginSizeInConversation = context.getResources().getDimensionPixelSize(
69                R.dimen.toast_bar_bottom_margin_in_conversation);
70        LayoutInflater.from(context).inflate(R.layout.actionable_toast_row, this, true);
71    }
72
73    @Override
74    protected void onFinishInflate() {
75        super.onFinishInflate();
76
77        mActionDescriptionIcon = (ImageView) findViewById(R.id.description_icon);
78        mActionDescriptionView = (TextView) findViewById(R.id.description_text);
79        mActionButton = findViewById(R.id.action_button);
80        mActionIcon = findViewById(R.id.action_icon);
81        mActionText = (TextView) findViewById(R.id.action_text);
82    }
83
84    /**
85     * Tells the view that it will be appearing in the conversation pane
86     * and should adjust its layout parameters accordingly.
87     * @param isInConversationMode true if the view will be shown in the conversation view
88     */
89    public void setConversationMode(boolean isInConversationMode) {
90        final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
91        params.bottomMargin = isInConversationMode ? mBottomMarginSizeInConversation : 0;
92        setLayoutParams(params);
93    }
94
95    /**
96     * Displays the toast bar and makes it visible. Allows the setting of
97     * parameters to customize the display.
98     * @param listener performs some action when the action button is clicked
99     * @param descriptionIconResourceId resource ID for the description icon or
100     * 0 if no icon should be shown
101     * @param descriptionText a description text to show in the toast bar
102     * @param showActionIcon if true, the action button icon should be shown
103     * @param actionTextResource resource ID for the text to show in the action button
104     * @param replaceVisibleToast if true, this toast should replace any currently visible toast.
105     * Otherwise, skip showing this toast.
106     */
107    public void show(final ActionClickedListener listener, int descriptionIconResourceId,
108            CharSequence descriptionText, boolean showActionIcon, int actionTextResource,
109            boolean replaceVisibleToast) {
110
111        if (!mHidden && !replaceVisibleToast) {
112            return;
113        }
114
115        mActionButton.setOnClickListener(new OnClickListener() {
116            @Override
117            public void onClick(View widget) {
118                if (listener != null) {
119                    listener.onActionClicked();
120                }
121                hide(true);
122            }
123        });
124
125        // Set description icon.
126        if (descriptionIconResourceId == 0) {
127            mActionDescriptionIcon.setVisibility(GONE);
128        } else {
129            mActionDescriptionIcon.setVisibility(VISIBLE);
130            mActionDescriptionIcon.setImageResource(descriptionIconResourceId);
131        }
132
133        mActionDescriptionView.setText(descriptionText);
134        mActionIcon.setVisibility(showActionIcon ? VISIBLE : GONE);
135        mActionText.setText(actionTextResource);
136
137        mHidden = false;
138        getShowAnimation().start();
139    }
140
141    /**
142     * Hides the view and resets the state.
143     */
144    public void hide(boolean animate) {
145        // Prevent multiple call to hide.
146        // Also prevent hiding if show animation is going on.
147        if (!mHidden && !getShowAnimation().isRunning()) {
148            mHidden = true;
149            if (getVisibility() == View.VISIBLE) {
150                mActionDescriptionView.setText("");
151                mActionButton.setOnClickListener(null);
152                // Hide view once it's clicked.
153                if (animate) {
154                    getHideAnimation().start();
155                } else {
156                    setAlpha(0);
157                    setVisibility(View.GONE);
158                }
159            }
160        }
161    }
162
163    private Animator getShowAnimation() {
164        if (mShowAnimation == null) {
165            mShowAnimation = AnimatorInflater.loadAnimator(getContext(), R.animator.fade_in);
166            mShowAnimation.addListener(new AnimatorListenerAdapter() {
167                @Override
168                public void onAnimationStart(Animator animation) {
169                    setVisibility(View.VISIBLE);
170                }
171
172                @Override
173                public void onAnimationEnd(Animator animation) {
174                    // There is a tiny change that and hide animation could have finished right
175                    // before the show animation finished.  In that case, the hide will mark the
176                    // view as GONE.  We need to make sure the last one wins.
177                    setVisibility(View.VISIBLE);
178                }
179            });
180            mShowAnimation.setTarget(this);
181        }
182        return mShowAnimation;
183    }
184
185    private Animator getHideAnimation() {
186        if (mHideAnimation == null) {
187            mHideAnimation = AnimatorInflater.loadAnimator(getContext(), R.animator.fade_out);
188            mHideAnimation.addListener(new AnimatorListenerAdapter() {
189                @Override
190                public void onAnimationEnd(Animator animation) {
191                    setVisibility(View.GONE);
192                }
193            });
194            mHideAnimation.setTarget(this);
195        }
196        return mHideAnimation;
197    }
198
199    public boolean isEventInToastBar(MotionEvent event) {
200        if (!isShown()) {
201            return false;
202        }
203        int[] xy = new int[2];
204        float x = event.getX();
205        float y = event.getY();
206        getLocationOnScreen(xy);
207        return (x > xy[0] && x < (xy[0] + getWidth()) && y > xy[1] && y < xy[1] + getHeight());
208    }
209
210    /**
211     * Classes that wish to perform some action when the action button is clicked
212     * should implement this interface.
213     */
214    public interface ActionClickedListener {
215        public void onActionClicked();
216    }
217}
218