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