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