ActionableToastBar.java revision d243d459b64003c5171ac5ff606729e525161be6
1/**
2 * Copyright (c) 2011, Google Inc.
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 */
16package com.android.mail.ui;
17
18import android.animation.Animator;
19import android.animation.AnimatorInflater;
20import android.content.Context;
21import android.text.Spanned;
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.mail.R;
32import com.android.mail.ui.ViewMode.ModeChangeListener;
33
34/**
35 * A custom {@link View} that exposes an action to the user.
36 */
37public class ActionableToastBar extends LinearLayout {
38    private boolean mHidden = false;
39    private Animator mShowAnimation;
40    private Animator mHideAnimation;
41    private final int mBottomMarginSizeInConversation;
42    private final int mBottomMarginSize;
43
44    /** Icon for the description. */
45    private ImageView mActionDescriptionIcon;
46    /** The clickable view */
47    private View mActionButton;
48    /** Icon for the action button. */
49    private View mActionIcon;
50    /** The view that contains the description. */
51    private TextView mActionDescriptionView;
52    /** The view that contains the text for the action button. */
53    private TextView mActionText;
54    private ToastBarOperation mOperation;
55
56    public ActionableToastBar(Context context) {
57        this(context, null);
58    }
59
60    public ActionableToastBar(Context context, AttributeSet attrs) {
61        this(context, attrs, 0);
62    }
63
64    public ActionableToastBar(Context context, AttributeSet attrs, int defStyle) {
65        super(context, attrs, defStyle);
66        mBottomMarginSize = context.getResources()
67                .getDimensionPixelSize(R.dimen.toast_bar_bottom_margin);
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
92                : mBottomMarginSize;
93        setLayoutParams(params);
94    }
95
96    /**
97     * Displays the toast bar and makes it visible. Allows the setting of
98     * parameters to customize the display.
99     * @param listener performs some action when the action button is clicked
100     * @param descriptionIconResourceId resource ID for the description icon or
101     * 0 if no icon should be shown
102     * @param descriptionText a description text to show in the toast bar
103     * @param showActionIcon if true, the action button icon should be shown
104     * @param actionTextResource resource ID for the text to show in the action button
105     * @param replaceVisibleToast if true, this toast should replace any currently visible toast.
106     * Otherwise, skip showing this toast.
107     * @param op the operation that corresponds to the specific toast being shown
108     */
109    public void show(final ActionClickedListener listener, int descriptionIconResourceId,
110            CharSequence descriptionText, boolean showActionIcon, int actionTextResource,
111            boolean replaceVisibleToast, ToastBarOperation op) {
112
113        if (!mHidden && !replaceVisibleToast) {
114            return;
115        }
116
117        mOperation = op;
118
119        mActionButton.setOnClickListener(new OnClickListener() {
120            @Override
121            public void onClick(View widget) {
122                listener.onActionClicked();
123                hide(true);
124            }
125        });
126
127        // Set description icon.
128        if (descriptionIconResourceId == 0) {
129            mActionDescriptionIcon.setVisibility(GONE);
130        } else {
131            mActionDescriptionIcon.setVisibility(VISIBLE);
132            mActionDescriptionIcon.setImageResource(descriptionIconResourceId);
133        }
134
135        mActionDescriptionView.setText(descriptionText);
136        mActionIcon.setVisibility(showActionIcon ? VISIBLE : GONE);
137        mActionText.setText(actionTextResource);
138
139        mHidden = false;
140        getShowAnimation().start();
141    }
142
143    public ToastBarOperation getOperation() {
144        return mOperation;
145    }
146
147    /**
148     * Hides the view and resets the state.
149     */
150    public void hide(boolean animate) {
151        mHidden = true;
152        if (getVisibility() == View.VISIBLE) {
153            mActionDescriptionView.setText("");
154            mActionButton.setOnClickListener(null);
155            // Hide view once it's clicked.
156            if (animate) {
157                getHideAnimation().start();
158            } else {
159                setAlpha(0);
160                setVisibility(View.GONE);
161            }
162        }
163    }
164
165    private Animator getShowAnimation() {
166        if (mShowAnimation == null) {
167            mShowAnimation = AnimatorInflater.loadAnimator(getContext(),
168                    R.anim.fade_in);
169            mShowAnimation.addListener(new Animator.AnimatorListener() {
170                @Override
171                public void onAnimationStart(Animator animation) {
172                    setVisibility(View.VISIBLE);
173                }
174                @Override
175                public void onAnimationEnd(Animator animation) {
176                }
177                @Override
178                public void onAnimationCancel(Animator animation) {
179                }
180                @Override
181                public void onAnimationRepeat(Animator animation) {
182                }
183            });
184            mShowAnimation.setTarget(this);
185        }
186        return mShowAnimation;
187    }
188
189    private Animator getHideAnimation() {
190        if (mHideAnimation == null) {
191            mHideAnimation = AnimatorInflater.loadAnimator(getContext(),
192                    R.anim.fade_out);
193            mHideAnimation.addListener(new Animator.AnimatorListener() {
194                @Override
195                public void onAnimationStart(Animator animation) {
196                }
197                @Override
198                public void onAnimationRepeat(Animator animation) {
199                }
200                @Override
201                public void onAnimationEnd(Animator animation) {
202                    setVisibility(View.GONE);
203                }
204                @Override
205                public void onAnimationCancel(Animator animation) {
206                }
207            });
208            mHideAnimation.setTarget(this);
209        }
210        return mHideAnimation;
211    }
212
213    public boolean isEventInToastBar(MotionEvent event) {
214        if (!isShown()) {
215            return false;
216        }
217        int[] xy = new int[2];
218        float x = event.getX();
219        float y = event.getY();
220        getLocationOnScreen(xy);
221        return (x > xy[0] && x < (xy[0] + getWidth()) && y > xy[1] && y < xy[1] + getHeight());
222    }
223
224    public boolean isAnimating() {
225        return mShowAnimation != null && mShowAnimation.isStarted();
226    }
227    /**
228     * Classes that wish to perform some action when the action button is clicked
229     * should implement this interface.
230     */
231    public interface ActionClickedListener {
232        public void onActionClicked();
233    }
234}
235