Snackbar.java revision b7f9224b1495db47eb8fd813b5912250e900770a
1b7f9224b1495db47eb8fd813b5912250e900770aChris Banes/*
2b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Copyright (C) 2015 The Android Open Source Project
3b7f9224b1495db47eb8fd813b5912250e900770aChris Banes *
4b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * you may not use this file except in compliance with the License.
6b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * You may obtain a copy of the License at
7b7f9224b1495db47eb8fd813b5912250e900770aChris Banes *
8b7f9224b1495db47eb8fd813b5912250e900770aChris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9b7f9224b1495db47eb8fd813b5912250e900770aChris Banes *
10b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Unless required by applicable law or agreed to in writing, software
11b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * See the License for the specific language governing permissions and
14b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * limitations under the License.
15b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */
16b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
17b7f9224b1495db47eb8fd813b5912250e900770aChris Banespackage android.support.design.widget;
18b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
19b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.content.Context;
20b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.content.res.TypedArray;
21b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Build;
22b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Handler;
23b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Looper;
24b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Message;
25b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.annotation.IntDef;
26b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.annotation.StringRes;
27b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.design.R;
28b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.v4.view.ViewCompat;
29b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
30b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.text.TextUtils;
31b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.util.AttributeSet;
32b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.LayoutInflater;
33b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.MotionEvent;
34b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.View;
35b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.ViewGroup;
36b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.animation.Animation;
37b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.animation.AnimationUtils;
38b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.widget.LinearLayout;
39b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.widget.TextView;
40b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
41b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport java.lang.annotation.Retention;
42b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport java.lang.annotation.RetentionPolicy;
43b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
44b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport static android.support.design.widget.AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR;
45b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
46b7f9224b1495db47eb8fd813b5912250e900770aChris Banes/**
47b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Snackbars provide lightweight feedback about an operation. They show a brief message at the
48b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * bottom of the screen on mobile and lower left on larger devices. Snackbars appear above all other
49b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * elements on screen and only one can be displayed at a time.
50b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * <p>
51b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * They automatically disappear after a timeout or after user interaction elsewhere on the screen,
52b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * particularly after interactions that summon a new surface or activity. Snackbars can be swiped
53b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * off screen.
54b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * <p>
55b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Snackbars can contain an action which is set via
56b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * {@link #setAction(CharSequence, android.view.View.OnClickListener)}.
57b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */
58b7f9224b1495db47eb8fd813b5912250e900770aChris Banespublic class Snackbar {
59b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
60b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
61b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @hide
62b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
63b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    @IntDef({LENGTH_SHORT, LENGTH_LONG})
64b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    @Retention(RetentionPolicy.SOURCE)
65b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public @interface Duration {}
66b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
67b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
68b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Show the Snackbar for a short period of time.
69b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
70b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @see #setDuration
71b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
72b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public static final int LENGTH_SHORT = -1;
73b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
74b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
75b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Show the Snackbar for a long period of time.
76b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
77b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @see #setDuration
78b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
79b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public static final int LENGTH_LONG = 0;
80b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
81b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private static final int ANIMATION_DURATION = 250;
82b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private static final int ANIMATION_FADE_DURATION = 180;
83b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
84b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private static final Handler sHandler;
85b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private static final int MSG_SHOW = 0;
86b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private static final int MSG_DISMISS = 1;
87b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
88b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    static {
89b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
90b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            @Override
91b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            public boolean handleMessage(Message message) {
92b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                switch (message.what) {
93b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    case MSG_SHOW:
94b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        ((Snackbar) message.obj).showView();
95b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        return true;
96b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    case MSG_DISMISS:
97b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        ((Snackbar) message.obj).hideView();
98b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        return true;
99b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
100b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                return false;
101b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
102b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        });
103b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
104b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
105b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private final ViewGroup mParent;
106b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private final Context mContext;
107b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private final SnackbarLayout mView;
108b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private int mDuration;
109b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
110b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    Snackbar(ViewGroup parent) {
111b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        mParent = parent;
112b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        mContext = parent.getContext();
113b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
114b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        LayoutInflater inflater = LayoutInflater.from(mContext);
115b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        mView = (SnackbarLayout) inflater.inflate(R.layout.layout_snackbar, mParent, false);
116b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
117b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
118b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
119b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Make a Snackbar to display a message.
120b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
121b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param parent   The parent to add Snackbars to.
122b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param text     The text to show.  Can be formatted text.
123b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or {@link
124b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *                 #LENGTH_LONG}
125b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
126b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public static Snackbar make(ViewGroup parent, CharSequence text, @Duration int duration) {
127b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        Snackbar snackbar = new Snackbar(parent);
128b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        snackbar.setText(text);
129b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        snackbar.setDuration(duration);
130b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return snackbar;
131b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
132b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
133b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
134b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Make a Snackbar to display a message.
135b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
136b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param parent   The parent to add Snackbars to.
137b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param resId    The resource id of the string resource to use.  Can be formatted text.
138b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or {@link
139b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *                 #LENGTH_LONG}
140b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
141b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public static Snackbar make(ViewGroup parent, int resId, @Duration int duration) {
142b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return make(parent, parent.getResources().getText(resId), duration);
143b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
144b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
145b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
146b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Set the action to be displayed in this {@link Snackbar}.
147b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
148b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param resId    String resource to display
149b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param listener callback to be invoked when the action is clicked
150b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
151b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public Snackbar setAction(@StringRes int resId, View.OnClickListener listener) {
152b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return setAction(mContext.getText(resId), listener);
153b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
154b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
155b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
156b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Set the action to be displayed in this {@link Snackbar}.
157b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
158b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param text     Text to display
159b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param listener callback to be invoked when the action is clicked
160b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
161b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public Snackbar setAction(CharSequence text, final View.OnClickListener listener) {
162b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        final TextView tv = mView.getActionView();
163b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
164b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        if (TextUtils.isEmpty(text) || listener == null) {
165b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            tv.setVisibility(View.GONE);
166b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            tv.setOnClickListener(null);
167b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        } else {
168b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            tv.setVisibility(View.VISIBLE);
169b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            tv.setText(text);
170b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            tv.setOnClickListener(new View.OnClickListener() {
171b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
172b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onClick(View view) {
173b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    listener.onClick(view);
174b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
175b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    // Now dismiss the Snackbar
176b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    dismiss();
177b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
178b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            });
179b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
180b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return this;
181b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
182b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
183b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
184b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Update the text in this {@link Snackbar}.
185b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
186b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param message The new text for the Toast.
187b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
188b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public Snackbar setText(CharSequence message) {
189b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        final TextView tv = mView.getMessageView();
190b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        tv.setText(message);
191b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return this;
192b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
193b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
194b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
195b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Update the text in this {@link Snackbar}.
196b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
197b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param resId The new text for the Toast.
198b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
199b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public Snackbar setText(@StringRes int resId) {
200b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return setText(mContext.getText(resId));
201b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
202b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
203b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
204b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Set how long to show the view for.
205b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
206b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @param duration either be one of the predefined lengths:
207b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *                 {@link #LENGTH_SHORT}, {@link #LENGTH_LONG}, or a custom duration
208b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *                 in milliseconds.
209b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
210b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public Snackbar setDuration(@Duration int duration) {
211b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        mDuration = duration;
212b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return this;
213b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
214b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
215b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
216b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Return the duration.
217b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     *
218b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @see #setDuration
219b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
220b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    @Duration
221b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public int getDuration() {
222b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return mDuration;
223b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
224b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
225b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
226b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Returns the {@link Snackbar}'s view.
227b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
228b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public View getView() {
229b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return mView;
230b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
231b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
232b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
233b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Show the {@link Snackbar}.
234b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
235b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public void show() {
236b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        SnackbarManager.getInstance().show(mDuration, mManagerCallback);
237b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
238b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
239b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
240b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * Dismiss the {@link Snackbar}.
241b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
242b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public void dismiss() {
243b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        SnackbarManager.getInstance().dismiss(mManagerCallback);
244b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
245b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
246b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
247b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        @Override
248b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        public void show() {
249b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, Snackbar.this));
250b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
251b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
252b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        @Override
253b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        public void dismiss() {
254b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            sHandler.sendMessage(sHandler.obtainMessage(MSG_DISMISS, Snackbar.this));
255b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
256b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    };
257b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
258b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    final void showView() {
259b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        if (mView.getParent() == null) {
260b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            final ViewGroup.LayoutParams lp = mView.getLayoutParams();
261b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
262b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (lp instanceof CoordinatorLayout.LayoutParams) {
263b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior
264b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
265b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                final Behavior behavior = new Behavior();
266b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                behavior.setStartAlphaSwipeDistance(0.1f);
267b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                behavior.setEndAlphaSwipeDistance(0.6f);
268b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END);
269b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {
270b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    @Override
271b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    public void onDismiss(View view) {
272b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        dismiss();
273b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    }
274b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
275b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    @Override
276b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    public void onDragStateChanged(int state) {
277b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        switch (state) {
278b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                            case SwipeDismissBehavior.STATE_DRAGGING:
279b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                            case SwipeDismissBehavior.STATE_SETTLING:
280b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                                // If the view is being dragged or settling, cancel the timeout
281b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                                SnackbarManager.getInstance().cancelTimeout(mManagerCallback);
282b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                                break;
283b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                            case SwipeDismissBehavior.STATE_IDLE:
284b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                                // If the view has been released and is idle, restore the timeout
285b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                                SnackbarManager.getInstance().restoreTimeout(mManagerCallback);
286b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                                break;
287b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        }
288b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    }
289b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                });
290b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                ((CoordinatorLayout.LayoutParams) lp).setBehavior(behavior);
291b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
292b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
293b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mParent.addView(mView);
294b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
295b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
296b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        if (ViewCompat.isLaidOut(mView)) {
297b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            // If the view is already laid out, animate it now
298b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            animateViewIn();
299b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        } else {
300b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            // Otherwise, add one of our layout change listeners and animate it in when laid out
301b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mView.setOnLayoutChangeListener(new SnackbarLayout.OnLayoutChangeListener() {
302b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
303b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onLayoutChange(View view, int left, int top, int right, int bottom) {
304b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    animateViewIn();
305b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    mView.setOnLayoutChangeListener(null);
306b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
307b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            });
308b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
309b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
310b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
311b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private void animateViewIn() {
312b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
313b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            ViewCompat.setTranslationY(mView, mView.getHeight());
314b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            ViewCompat.animate(mView).translationY(0f)
315b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
316b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setDuration(ANIMATION_DURATION)
317b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setListener(new ViewPropertyAnimatorListenerAdapter() {
318b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        @Override
319b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        public void onAnimationStart(View view) {
320b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                            mView.animateChildrenIn(ANIMATION_DURATION - ANIMATION_FADE_DURATION,
321b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                                    ANIMATION_FADE_DURATION);
322b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        }
323b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
324b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        @Override
325b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        public void onAnimationEnd(View view) {
326b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                            SnackbarManager.getInstance().onShown(mManagerCallback);
327b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        }
328b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    }).start();
329b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        } else {
330b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.snackbar_in);
331b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
332b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            anim.setDuration(ANIMATION_DURATION);
333b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            anim.setAnimationListener(new Animation.AnimationListener() {
334b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
335b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onAnimationEnd(Animation animation) {
336b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    SnackbarManager.getInstance().onShown(mManagerCallback);
337b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
338b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
339b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
340b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onAnimationStart(Animation animation) {}
341b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
342b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
343b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onAnimationRepeat(Animation animation) {}
344b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            });
345b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mView.startAnimation(anim);
346b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
347b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
348b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
349b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private void animateViewOut() {
350b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
351b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            ViewCompat.animate(mView).translationY(mView.getHeight())
352b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
353b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setDuration(ANIMATION_DURATION)
354b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setListener(new ViewPropertyAnimatorListenerAdapter() {
355b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        @Override
356b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        public void onAnimationStart(View view) {
357b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                            mView.animateChildrenOut(0, ANIMATION_FADE_DURATION);
358b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        }
359b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
360b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        @Override
361b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        public void onAnimationEnd(View view) {
362b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                            onViewHidden();
363b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        }
364b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    }).start();
365b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        } else {
366b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.snackbar_out);
367b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
368b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            anim.setDuration(ANIMATION_DURATION);
369b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            anim.setAnimationListener(new Animation.AnimationListener() {
370b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
371b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onAnimationEnd(Animation animation) {
372b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    onViewHidden();
373b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
374b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
375b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
376b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onAnimationStart(Animation animation) {}
377b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
378b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                @Override
379b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                public void onAnimationRepeat(Animation animation) {}
380b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            });
381b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mView.startAnimation(anim);
382b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
383b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
384b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
385b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    final void hideView() {
386b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        if (mView.getVisibility() != View.VISIBLE || isBeingDragged()) {
387b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            onViewHidden();
388b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        } else {
389b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            animateViewOut();
390b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
391b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
392b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
393b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private void onViewHidden() {
394b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        // First remove the view from the parent
395b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        mParent.removeView(mView);
396b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        // Now, tell the SnackbarManager that it has been dismissed
397b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        SnackbarManager.getInstance().onDismissed(mManagerCallback);
398b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
399b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
400b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
401b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @return if the view is being being dragged or settled by {@link SwipeDismissBehavior}.
402b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
403b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    private boolean isBeingDragged() {
404b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        final ViewGroup.LayoutParams lp = mView.getLayoutParams();
405b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
406b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        if (lp instanceof CoordinatorLayout.LayoutParams) {
407b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            final CoordinatorLayout.LayoutParams cllp = (CoordinatorLayout.LayoutParams) lp;
408b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            final CoordinatorLayout.Behavior behavior = cllp.getBehavior();
409b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
410b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (behavior instanceof SwipeDismissBehavior) {
411b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                return ((SwipeDismissBehavior) behavior).getDragState()
412b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        != SwipeDismissBehavior.STATE_IDLE;
413b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
414b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
415b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        return false;
416b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
417b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
418b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    /**
419b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     * @hide
420b7f9224b1495db47eb8fd813b5912250e900770aChris Banes     */
421b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    public static class SnackbarLayout extends LinearLayout {
422b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        private TextView mMessageView;
423b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        private TextView mActionView;
424b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
425b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        private int mMaxWidth;
426b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        private int mMaxInlineActionWidth;
427b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
428b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        interface OnLayoutChangeListener {
429b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            public void onLayoutChange(View view, int left, int top, int right, int bottom);
430b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
431b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
432b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        private OnLayoutChangeListener mOnLayoutChangeListener;
433b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
434b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        public SnackbarLayout(Context context) {
435b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            this(context, null);
436b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
437b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
438b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        public SnackbarLayout(Context context, AttributeSet attrs) {
439b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            super(context, attrs);
440b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SnackbarLayout);
441b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mMaxWidth = a.getDimensionPixelSize(R.styleable.SnackbarLayout_android_maxWidth, -1);
442b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mMaxInlineActionWidth = a.getDimensionPixelSize(
443b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    R.styleable.SnackbarLayout_maxActionInlineWidth, -1);
444b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            a.recycle();
445b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
446b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            setClickable(true);
447b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
448b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            // Now inflate our content. We need to do this manually rather than using an <include>
449b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            // in the layout since older versions of the Android do not inflate includes with
450b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            // the correct Context.
451b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            LayoutInflater.from(context).inflate(R.layout.layout_snackbar_include, this);
452b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
453b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
454b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        @Override
455b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        protected void onFinishInflate() {
456b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            super.onFinishInflate();
457b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mMessageView = (TextView) findViewById(R.id.snackbar_text);
458b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mActionView = (TextView) findViewById(R.id.snackbar_action);
459b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
460b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
461b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        TextView getMessageView() {
462b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            return mMessageView;
463b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
464b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
465b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        TextView getActionView() {
466b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            return mActionView;
467b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
468b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
469b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        @Override
470b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
471b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
472b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
473b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (mMaxWidth > 0 && getMeasuredWidth() > mMaxWidth) {
474b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY);
475b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
476b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
477b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
478b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            final int multiLineVPadding = getResources().getDimensionPixelSize(
479b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    R.dimen.snackbar_padding_vertical_2lines);
480b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            final int singleLineVPadding = getResources().getDimensionPixelSize(
481b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    R.dimen.snackbar_padding_vertical);
482b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            final boolean isMultiLine = mMessageView.getLayout().getLineCount() > 1;
483b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
484b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            boolean remeasure = false;
485b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (isMultiLine && mMaxInlineActionWidth > 0
486b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    && mActionView.getMeasuredWidth() > mMaxInlineActionWidth) {
487b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                if (updateViewsWithinLayout(VERTICAL, multiLineVPadding,
488b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        multiLineVPadding - singleLineVPadding)) {
489b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    remeasure = true;
490b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
491b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            } else {
492b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                final int messagePadding = isMultiLine ? multiLineVPadding : singleLineVPadding;
493b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                if (updateViewsWithinLayout(HORIZONTAL, messagePadding, messagePadding)) {
494b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    remeasure = true;
495b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
496b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
497b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
498b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (remeasure) {
499b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
500b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
501b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
502b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
503b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        void animateChildrenIn(int delay, int duration) {
504b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            ViewCompat.setAlpha(mMessageView, 0f);
505b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            ViewCompat.animate(mMessageView).alpha(1f).setDuration(duration)
506b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setStartDelay(delay).start();
507b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
508b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (mActionView.getVisibility() == VISIBLE) {
509b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                ViewCompat.setAlpha(mActionView, 0f);
510b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                ViewCompat.animate(mActionView).alpha(1f).setDuration(duration)
511b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        .setStartDelay(delay).start();
512b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
513b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
514b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
515b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        void animateChildrenOut(int delay, int duration) {
516b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            ViewCompat.setAlpha(mMessageView, 1f);
517b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            ViewCompat.animate(mMessageView).alpha(0f).setDuration(duration)
518b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    .setStartDelay(delay).start();
519b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
520b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (mActionView.getVisibility() == VISIBLE) {
521b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                ViewCompat.setAlpha(mActionView, 1f);
522b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                ViewCompat.animate(mActionView).alpha(0f).setDuration(duration)
523b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        .setStartDelay(delay).start();
524b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
525b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
526b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
527b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        @Override
528b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        protected void onLayout(boolean changed, int l, int t, int r, int b) {
529b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            super.onLayout(changed, l, t, r, b);
530b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (changed && mOnLayoutChangeListener != null) {
531b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                mOnLayoutChangeListener.onLayoutChange(this, l, t, r, b);
532b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
533b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
534b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
535b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        void setOnLayoutChangeListener(OnLayoutChangeListener onLayoutChangeListener) {
536b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            mOnLayoutChangeListener = onLayoutChangeListener;
537b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
538b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
539b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        private boolean updateViewsWithinLayout(final int orientation,
540b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                final int messagePadTop, final int messagePadBottom) {
541b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            boolean changed = false;
542b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (orientation != getOrientation()) {
543b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                setOrientation(orientation);
544b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                changed = true;
545b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
546b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (mMessageView.getPaddingTop() != messagePadTop
547b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    || mMessageView.getPaddingBottom() != messagePadBottom) {
548b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                updateTopBottomPadding(mMessageView, messagePadTop, messagePadBottom);
549b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                changed = true;
550b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
551b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            return changed;
552b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
553b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
554b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        private static void updateTopBottomPadding(View view, int topPadding, int bottomPadding) {
555b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (ViewCompat.isPaddingRelative(view)) {
556b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                ViewCompat.setPaddingRelative(view,
557b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        ViewCompat.getPaddingStart(view), topPadding,
558b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        ViewCompat.getPaddingEnd(view), bottomPadding);
559b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            } else {
560b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                view.setPadding(view.getPaddingLeft(), topPadding,
561b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        view.getPaddingRight(), bottomPadding);
562b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
563b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
564b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
565b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
566b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    final class Behavior extends SwipeDismissBehavior<SnackbarLayout> {
567b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        @Override
568b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        public boolean onInterceptTouchEvent(CoordinatorLayout parent, SnackbarLayout child,
569b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                MotionEvent event) {
570b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            // We want to make sure that we disable any Snackbar timeouts if the user is
571b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            // currently touching the Snackbar. We restore the timeout when complete
572b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            if (parent.isPointInChildBounds(child, (int) event.getX(), (int) event.getY())) {
573b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                switch (event.getActionMasked()) {
574b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    case MotionEvent.ACTION_DOWN:
575b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        SnackbarManager.getInstance().cancelTimeout(mManagerCallback);
576b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        break;
577b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    case MotionEvent.ACTION_UP:
578b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                    case MotionEvent.ACTION_CANCEL:
579b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        SnackbarManager.getInstance().restoreTimeout(mManagerCallback);
580b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                        break;
581b7f9224b1495db47eb8fd813b5912250e900770aChris Banes                }
582b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            }
583b7f9224b1495db47eb8fd813b5912250e900770aChris Banes
584b7f9224b1495db47eb8fd813b5912250e900770aChris Banes            return super.onInterceptTouchEvent(parent, child, event);
585b7f9224b1495db47eb8fd813b5912250e900770aChris Banes        }
586b7f9224b1495db47eb8fd813b5912250e900770aChris Banes    }
587b7f9224b1495db47eb8fd813b5912250e900770aChris Banes}
588