Snackbar.java revision a89b7a8e4840e52dfda1442bcb885686680556f6
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; 204112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banesimport android.content.res.ColorStateList; 21b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.content.res.TypedArray; 22b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Build; 23b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Handler; 24b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Looper; 25b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.os.Message; 265bb1f5d910c81ed2a31c687583bd90baccc972acChris Banesimport android.support.annotation.ColorInt; 27b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.annotation.IntDef; 285bb1f5d910c81ed2a31c687583bd90baccc972acChris Banesimport android.support.annotation.NonNull; 29b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.annotation.StringRes; 30b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.design.R; 31b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.v4.view.ViewCompat; 32b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.support.v4.view.ViewPropertyAnimatorListenerAdapter; 33b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.text.TextUtils; 34b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.util.AttributeSet; 35b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.LayoutInflater; 36b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.MotionEvent; 37b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.View; 38b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.ViewGroup; 39c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banesimport android.view.ViewParent; 40ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banesimport android.view.accessibility.AccessibilityManager; 41b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.animation.Animation; 42b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.view.animation.AnimationUtils; 435cf1a7e04097b7e116c118cfa823a4cdb48f38a1Chris Banesimport android.widget.Button; 44c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banesimport android.widget.FrameLayout; 45b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.widget.LinearLayout; 46b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport android.widget.TextView; 47b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 48b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport java.lang.annotation.Retention; 49b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport java.lang.annotation.RetentionPolicy; 50b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 51b7f9224b1495db47eb8fd813b5912250e900770aChris Banesimport static android.support.design.widget.AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR; 52b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 53b7f9224b1495db47eb8fd813b5912250e900770aChris Banes/** 54b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Snackbars provide lightweight feedback about an operation. They show a brief message at the 55b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * bottom of the screen on mobile and lower left on larger devices. Snackbars appear above all other 56b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * elements on screen and only one can be displayed at a time. 57b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * <p> 58b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * They automatically disappear after a timeout or after user interaction elsewhere on the screen, 59b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * particularly after interactions that summon a new surface or activity. Snackbars can be swiped 60b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * off screen. 61b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * <p> 62b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Snackbars can contain an action which is set via 63b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * {@link #setAction(CharSequence, android.view.View.OnClickListener)}. 64bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * <p> 65bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * To be notified when a snackbar has been shown or dismissed, you can provide a {@link Callback} 66bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * via {@link #setCallback(Callback)}.</p> 67b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 68e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banespublic final class Snackbar { 69b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 70b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 71bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * Callback class for {@link Snackbar} instances. 72bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * 73bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * @see Snackbar#setCallback(Callback) 74bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes */ 75bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes public static abstract class Callback { 76e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes /** Indicates that the Snackbar was dismissed via a swipe.*/ 77e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public static final int DISMISS_EVENT_SWIPE = 0; 78e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes /** Indicates that the Snackbar was dismissed via an action click.*/ 79e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public static final int DISMISS_EVENT_ACTION = 1; 80e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes /** Indicates that the Snackbar was dismissed via a timeout.*/ 81e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public static final int DISMISS_EVENT_TIMEOUT = 2; 82e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes /** Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}.*/ 83e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public static final int DISMISS_EVENT_MANUAL = 3; 84e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes /** Indicates that the Snackbar was dismissed from a new Snackbar being shown.*/ 85e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public static final int DISMISS_EVENT_CONSECUTIVE = 4; 86e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes 87e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes /** @hide */ 88e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @IntDef({DISMISS_EVENT_SWIPE, DISMISS_EVENT_ACTION, DISMISS_EVENT_TIMEOUT, 89e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes DISMISS_EVENT_MANUAL, DISMISS_EVENT_CONSECUTIVE}) 90e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @Retention(RetentionPolicy.SOURCE) 91e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public @interface DismissEvent {} 92e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes 93bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes /** 94bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * Called when the given {@link Snackbar} has been dismissed, either through a time-out, 95bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * having been manually dismissed, or an action being clicked. 96bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * 97bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * @param snackbar The snackbar which has been dismissed. 98e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes * @param event The event which caused the dismissal. One of either: 99e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes * {@link #DISMISS_EVENT_SWIPE}, {@link #DISMISS_EVENT_ACTION}, 100e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes * {@link #DISMISS_EVENT_TIMEOUT}, {@link #DISMISS_EVENT_MANUAL} or 101e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes * {@link #DISMISS_EVENT_CONSECUTIVE}. 102e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes * 103bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * @see Snackbar#dismiss() 104bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes */ 105e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public void onDismissed(Snackbar snackbar, @DismissEvent int event) { 106bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes // empty 107bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes } 108bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes 109bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes /** 110bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * Called when the given {@link Snackbar} is visible. 111bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * 112bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * @param snackbar The snackbar which is now visible. 113bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * @see Snackbar#show() 114bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes */ 115bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes public void onShown(Snackbar snackbar) { 116bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes // empty 117bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes } 118bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes } 119bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes 120bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes /** 121b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @hide 122b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 1230bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes @IntDef({LENGTH_INDEFINITE, LENGTH_SHORT, LENGTH_LONG}) 124b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Retention(RetentionPolicy.SOURCE) 125b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public @interface Duration {} 126b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 127b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 1280bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes * Show the Snackbar indefinitely. This means that the Snackbar will be displayed from the time 1290bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes * that is {@link #show() shown} until either it is dismissed, or another Snackbar is shown. 1300bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes * 1310bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes * @see #setDuration 1320bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes */ 1330bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes public static final int LENGTH_INDEFINITE = -2; 1340bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes 1350bfb0e034ed6b4f7bbf58a111d2fc893e0553350Chris Banes /** 136b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Show the Snackbar for a short period of time. 137b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 138b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @see #setDuration 139b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 140b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static final int LENGTH_SHORT = -1; 141b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 142b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 143b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Show the Snackbar for a long period of time. 144b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 145b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @see #setDuration 146b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 147b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static final int LENGTH_LONG = 0; 148b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 149df00f11c8c90db7b26672267fd1b74250c0d6cefChris Banes static final int ANIMATION_DURATION = 250; 150df00f11c8c90db7b26672267fd1b74250c0d6cefChris Banes static final int ANIMATION_FADE_DURATION = 180; 151b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 152b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final Handler sHandler; 153b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final int MSG_SHOW = 0; 154b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static final int MSG_DISMISS = 1; 155b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 156b7f9224b1495db47eb8fd813b5912250e900770aChris Banes static { 157b7f9224b1495db47eb8fd813b5912250e900770aChris Banes sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() { 158b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 159b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public boolean handleMessage(Message message) { 160b7f9224b1495db47eb8fd813b5912250e900770aChris Banes switch (message.what) { 161b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MSG_SHOW: 162b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ((Snackbar) message.obj).showView(); 163b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return true; 164b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MSG_DISMISS: 165e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes ((Snackbar) message.obj).hideView(message.arg1); 166b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return true; 167b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 168b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return false; 169b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 170b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 171b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 172b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 1735462d3e588481416a38e893bdb0f1073f82f8dccChris Banes private final ViewGroup mTargetParent; 174b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private final Context mContext; 175b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private final SnackbarLayout mView; 176b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private int mDuration; 177bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes private Callback mCallback; 178b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 179ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes private final AccessibilityManager mAccessibilityManager; 180ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes 181e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes private Snackbar(ViewGroup parent) { 1825462d3e588481416a38e893bdb0f1073f82f8dccChris Banes mTargetParent = parent; 183b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mContext = parent.getContext(); 184b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 185809bb62055ad42b88f3a69308be222801b89fbd9Chris Banes ThemeUtils.checkAppCompatTheme(mContext); 186809bb62055ad42b88f3a69308be222801b89fbd9Chris Banes 187b7f9224b1495db47eb8fd813b5912250e900770aChris Banes LayoutInflater inflater = LayoutInflater.from(mContext); 1885462d3e588481416a38e893bdb0f1073f82f8dccChris Banes mView = (SnackbarLayout) inflater.inflate( 1895462d3e588481416a38e893bdb0f1073f82f8dccChris Banes R.layout.design_layout_snackbar, mTargetParent, false); 190ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes 191ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes mAccessibilityManager = (AccessibilityManager) 192ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 193b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 194b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 195b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 196c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * Make a Snackbar to display a message 197c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * 198c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * <p>Snackbar will try and find a parent view to hold Snackbar's view from the value given 199c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * to {@code view}. Snackbar will walk up the view tree trying to find a suitable parent, 200c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * which is defined as a {@link CoordinatorLayout} or the window decor's content view, 201c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * whichever comes first. 202c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * 203c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * <p>Having a {@link CoordinatorLayout} in your view hierarchy allows Snackbar to enable 204c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * certain features, such as swipe-to-dismiss and automatically moving of widgets like 205c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * {@link FloatingActionButton}. 206b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 207c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * @param view The view to find a parent from. 208b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param text The text to show. Can be formatted text. 209b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param duration How long to display the message. Either {@link #LENGTH_SHORT} or {@link 210b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * #LENGTH_LONG} 211b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 212e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 2135bb1f5d910c81ed2a31c687583bd90baccc972acChris Banes public static Snackbar make(@NonNull View view, @NonNull CharSequence text, 2145bb1f5d910c81ed2a31c687583bd90baccc972acChris Banes @Duration int duration) { 215c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes Snackbar snackbar = new Snackbar(findSuitableParent(view)); 216b7f9224b1495db47eb8fd813b5912250e900770aChris Banes snackbar.setText(text); 217b7f9224b1495db47eb8fd813b5912250e900770aChris Banes snackbar.setDuration(duration); 218b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return snackbar; 219b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 220b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 221b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 222b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Make a Snackbar to display a message. 223b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 224c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * <p>Snackbar will try and find a parent view to hold Snackbar's view from the value given 225c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * to {@code view}. Snackbar will walk up the view tree trying to find a suitable parent, 226c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * which is defined as a {@link CoordinatorLayout} or the window decor's content view, 227c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * whichever comes first. 228c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * 229c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * <p>Having a {@link CoordinatorLayout} in your view hierarchy allows Snackbar to enable 230c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * certain features, such as swipe-to-dismiss and automatically moving of widgets like 231c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * {@link FloatingActionButton}. 232c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * 233c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * @param view The view to find a parent from. 234c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes * @param resId The resource id of the string resource to use. Can be formatted text. 235b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param duration How long to display the message. Either {@link #LENGTH_SHORT} or {@link 236b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * #LENGTH_LONG} 237b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 238e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 2395bb1f5d910c81ed2a31c687583bd90baccc972acChris Banes public static Snackbar make(@NonNull View view, @StringRes int resId, @Duration int duration) { 240c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes return make(view, view.getResources().getText(resId), duration); 241c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes } 242c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes 243c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes private static ViewGroup findSuitableParent(View view) { 244c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes ViewGroup fallback = null; 245c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes do { 246c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes if (view instanceof CoordinatorLayout) { 247c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes // We've found a CoordinatorLayout, use it 248c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes return (ViewGroup) view; 249c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes } else if (view instanceof FrameLayout) { 250c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes if (view.getId() == android.R.id.content) { 251c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes // If we've hit the decor content view, then we didn't find a CoL in the 252c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes // hierarchy, so use it. 253c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes return (ViewGroup) view; 254c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes } else { 255c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes // It's not the content view but we'll use it as our fallback 256c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes fallback = (ViewGroup) view; 257c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes } 258c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes } 259c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes 260c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes if (view != null) { 261c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes // Else, we will loop and crawl up the view hierarchy and try to find a parent 262c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes final ViewParent parent = view.getParent(); 263c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes view = parent instanceof View ? (View) parent : null; 264c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes } 265c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes } while (view != null); 266c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes 267c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes // If we reach here then we didn't find a CoL or a suitable content view so we'll fallback 268c482f89070ee5032081e394f77a9a1e63c3cd7a8Chris Banes return fallback; 269b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 270b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 271b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 272b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Set the action to be displayed in this {@link Snackbar}. 273b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 274b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param resId String resource to display 275b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param listener callback to be invoked when the action is clicked 276b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 277e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 278b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setAction(@StringRes int resId, View.OnClickListener listener) { 279b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return setAction(mContext.getText(resId), listener); 280b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 281b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 282b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 283b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Set the action to be displayed in this {@link Snackbar}. 284b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 285b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param text Text to display 286b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param listener callback to be invoked when the action is clicked 287b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 288e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 289b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setAction(CharSequence text, final View.OnClickListener listener) { 290b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final TextView tv = mView.getActionView(); 291b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 292b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (TextUtils.isEmpty(text) || listener == null) { 293b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setVisibility(View.GONE); 294b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setOnClickListener(null); 295b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 296b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setVisibility(View.VISIBLE); 297b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setText(text); 298b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setOnClickListener(new View.OnClickListener() { 299b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 300b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onClick(View view) { 301b7f9224b1495db47eb8fd813b5912250e900770aChris Banes listener.onClick(view); 302b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // Now dismiss the Snackbar 303e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes dispatchDismiss(Callback.DISMISS_EVENT_ACTION); 304b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 305b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 306b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 307b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return this; 308b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 309b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 310b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 3114112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes * Sets the text color of the action specified in 3124112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes * {@link #setAction(CharSequence, View.OnClickListener)}. 3134112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes */ 314e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 3154112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes public Snackbar setActionTextColor(ColorStateList colors) { 3164112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes final TextView tv = mView.getActionView(); 3174112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes tv.setTextColor(colors); 3184112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes return this; 3194112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes } 3204112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes 3214112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes /** 3224112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes * Sets the text color of the action specified in 3234112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes * {@link #setAction(CharSequence, View.OnClickListener)}. 3244112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes */ 325e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 3265bb1f5d910c81ed2a31c687583bd90baccc972acChris Banes public Snackbar setActionTextColor(@ColorInt int color) { 3274112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes final TextView tv = mView.getActionView(); 3284112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes tv.setTextColor(color); 3294112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes return this; 3304112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes } 3314112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes 3324112c61626e5a6107c5874c28829b76bb9fc9f17Chris Banes /** 333b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Update the text in this {@link Snackbar}. 334b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 335b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param message The new text for the Toast. 336b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 337e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 3385bb1f5d910c81ed2a31c687583bd90baccc972acChris Banes public Snackbar setText(@NonNull CharSequence message) { 339b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final TextView tv = mView.getMessageView(); 340b7f9224b1495db47eb8fd813b5912250e900770aChris Banes tv.setText(message); 341b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return this; 342b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 343b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 344b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 345b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Update the text in this {@link Snackbar}. 346b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 347b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param resId The new text for the Toast. 348b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 349e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 350b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setText(@StringRes int resId) { 351b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return setText(mContext.getText(resId)); 352b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 353b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 354b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 355b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Set how long to show the view for. 356b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 357b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @param duration either be one of the predefined lengths: 358b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * {@link #LENGTH_SHORT}, {@link #LENGTH_LONG}, or a custom duration 359b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * in milliseconds. 360b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 361e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 362b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public Snackbar setDuration(@Duration int duration) { 363b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mDuration = duration; 364b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return this; 365b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 366b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 367b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 368b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Return the duration. 369b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * 370b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @see #setDuration 371b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 372b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Duration 373b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public int getDuration() { 374b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mDuration; 375b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 376b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 377b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 378b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Returns the {@link Snackbar}'s view. 379b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 3805bb1f5d910c81ed2a31c687583bd90baccc972acChris Banes @NonNull 381b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public View getView() { 382b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mView; 383b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 384b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 385b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 386b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Show the {@link Snackbar}. 387b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 388b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void show() { 389b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().show(mDuration, mManagerCallback); 390b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 391b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 392b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 393b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * Dismiss the {@link Snackbar}. 394b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 395b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void dismiss() { 396e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes dispatchDismiss(Callback.DISMISS_EVENT_MANUAL); 397e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes } 398e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes 399e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes private void dispatchDismiss(@Callback.DismissEvent int event) { 400e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes SnackbarManager.getInstance().dismiss(mManagerCallback, event); 401b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 402b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 403bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes /** 404bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes * Set a callback to be called when this the visibility of this {@link Snackbar} changes. 405bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes */ 406e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes @NonNull 407e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public Snackbar setCallback(Callback callback) { 408bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes mCallback = callback; 409e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes return this; 410e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes } 411e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes 412e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes /** 4135462d3e588481416a38e893bdb0f1073f82f8dccChris Banes * Return whether this {@link Snackbar} is currently being shown. 414e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes */ 415e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public boolean isShown() { 4165462d3e588481416a38e893bdb0f1073f82f8dccChris Banes return SnackbarManager.getInstance().isCurrent(mManagerCallback); 4175462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 4185462d3e588481416a38e893bdb0f1073f82f8dccChris Banes 4195462d3e588481416a38e893bdb0f1073f82f8dccChris Banes /** 4205462d3e588481416a38e893bdb0f1073f82f8dccChris Banes * Returns whether this {@link Snackbar} is currently being shown, or is queued to be 4215462d3e588481416a38e893bdb0f1073f82f8dccChris Banes * shown next. 4225462d3e588481416a38e893bdb0f1073f82f8dccChris Banes */ 4235462d3e588481416a38e893bdb0f1073f82f8dccChris Banes public boolean isShownOrQueued() { 4245462d3e588481416a38e893bdb0f1073f82f8dccChris Banes return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback); 425bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes } 426bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes 427b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() { 428b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 429b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void show() { 430b7f9224b1495db47eb8fd813b5912250e900770aChris Banes sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, Snackbar.this)); 431b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 432b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 433b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 434e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes public void dismiss(int event) { 435e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes sHandler.sendMessage(sHandler.obtainMessage(MSG_DISMISS, event, 0, Snackbar.this)); 436b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 437b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }; 438b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 439b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final void showView() { 440b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mView.getParent() == null) { 441b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final ViewGroup.LayoutParams lp = mView.getLayoutParams(); 442b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 443b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (lp instanceof CoordinatorLayout.LayoutParams) { 444b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior 445b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 446b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final Behavior behavior = new Behavior(); 447b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setStartAlphaSwipeDistance(0.1f); 448b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setEndAlphaSwipeDistance(0.6f); 449b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END); 450b7f9224b1495db47eb8fd813b5912250e900770aChris Banes behavior.setListener(new SwipeDismissBehavior.OnDismissListener() { 451b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 452b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onDismiss(View view) { 453a89b7a8e4840e52dfda1442bcb885686680556f6Chris Banes view.setVisibility(View.GONE); 454e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes dispatchDismiss(Callback.DISMISS_EVENT_SWIPE); 455b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 456b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 457b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 458b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onDragStateChanged(int state) { 459b7f9224b1495db47eb8fd813b5912250e900770aChris Banes switch (state) { 460b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case SwipeDismissBehavior.STATE_DRAGGING: 461b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case SwipeDismissBehavior.STATE_SETTLING: 462b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If the view is being dragged or settling, cancel the timeout 463b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().cancelTimeout(mManagerCallback); 464b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 465b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case SwipeDismissBehavior.STATE_IDLE: 466b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If the view has been released and is idle, restore the timeout 467b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().restoreTimeout(mManagerCallback); 468b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 469b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 470b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 471b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 472b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ((CoordinatorLayout.LayoutParams) lp).setBehavior(behavior); 473b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 474b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 4755462d3e588481416a38e893bdb0f1073f82f8dccChris Banes mTargetParent.addView(mView); 476b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 477b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 4785462d3e588481416a38e893bdb0f1073f82f8dccChris Banes mView.setOnAttachStateChangeListener(new SnackbarLayout.OnAttachStateChangeListener() { 4795462d3e588481416a38e893bdb0f1073f82f8dccChris Banes @Override 4805462d3e588481416a38e893bdb0f1073f82f8dccChris Banes public void onViewAttachedToWindow(View v) {} 4815462d3e588481416a38e893bdb0f1073f82f8dccChris Banes 4825462d3e588481416a38e893bdb0f1073f82f8dccChris Banes @Override 4835462d3e588481416a38e893bdb0f1073f82f8dccChris Banes public void onViewDetachedFromWindow(View v) { 4845462d3e588481416a38e893bdb0f1073f82f8dccChris Banes if (isShownOrQueued()) { 4855462d3e588481416a38e893bdb0f1073f82f8dccChris Banes // If we haven't already been dismissed then this event is coming from a 4865462d3e588481416a38e893bdb0f1073f82f8dccChris Banes // non-user initiated action. Hence we need to make sure that we callback 4875462d3e588481416a38e893bdb0f1073f82f8dccChris Banes // and keep our state up to date. We need to post the call since removeView() 4885462d3e588481416a38e893bdb0f1073f82f8dccChris Banes // will call through to onDetachedFromWindow and thus overflow. 4895462d3e588481416a38e893bdb0f1073f82f8dccChris Banes sHandler.post(new Runnable() { 4905462d3e588481416a38e893bdb0f1073f82f8dccChris Banes @Override 4915462d3e588481416a38e893bdb0f1073f82f8dccChris Banes public void run() { 4925462d3e588481416a38e893bdb0f1073f82f8dccChris Banes onViewHidden(Callback.DISMISS_EVENT_MANUAL); 4935462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 4945462d3e588481416a38e893bdb0f1073f82f8dccChris Banes }); 4955462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 4965462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 4975462d3e588481416a38e893bdb0f1073f82f8dccChris Banes }); 4985462d3e588481416a38e893bdb0f1073f82f8dccChris Banes 499b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (ViewCompat.isLaidOut(mView)) { 500b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // If the view is already laid out, animate it now 501b7f9224b1495db47eb8fd813b5912250e900770aChris Banes animateViewIn(); 502b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 503b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // Otherwise, add one of our layout change listeners and animate it in when laid out 504b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.setOnLayoutChangeListener(new SnackbarLayout.OnLayoutChangeListener() { 505b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 506b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onLayoutChange(View view, int left, int top, int right, int bottom) { 507b7f9224b1495db47eb8fd813b5912250e900770aChris Banes animateViewIn(); 508b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.setOnLayoutChangeListener(null); 509b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 510b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 511b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 512b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 513b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 514b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private void animateViewIn() { 515b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 516b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setTranslationY(mView, mView.getHeight()); 5173224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes ViewCompat.animate(mView) 5183224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes .translationY(0f) 519b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR) 520b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setDuration(ANIMATION_DURATION) 521b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setListener(new ViewPropertyAnimatorListenerAdapter() { 522b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 523b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(View view) { 524ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes if (!mAccessibilityManager.isEnabled()) { 525ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // Animating the children in causes Talkback to think that they're 526ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // not visible when the TYPE_WINDOW_CONTENT_CHANGED event if fired. 527ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // Fixed by skipping the animation when an accessibility manager 528ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // is enabled 529ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes mView.animateChildrenIn( 530ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes ANIMATION_DURATION - ANIMATION_FADE_DURATION, 531ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes ANIMATION_FADE_DURATION); 532ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes } 533b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 534b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 535b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 536b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(View view) { 537bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes onViewShown(); 538b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 539b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }).start(); 540b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 5413224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes Animation anim = AnimationUtils.loadAnimation(mView.getContext(), 5423224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes R.anim.design_snackbar_in); 543b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR); 544b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setDuration(ANIMATION_DURATION); 545b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setAnimationListener(new Animation.AnimationListener() { 546b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 547b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(Animation animation) { 548bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes onViewShown(); 549b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 550b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 551b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 552b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(Animation animation) {} 553b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 554b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 555b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationRepeat(Animation animation) {} 556b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 557b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.startAnimation(anim); 558b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 559b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 560b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 561e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes private void animateViewOut(final int event) { 562b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5633224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes ViewCompat.animate(mView) 5643224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes .translationY(mView.getHeight()) 565b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR) 566b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setDuration(ANIMATION_DURATION) 567b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setListener(new ViewPropertyAnimatorListenerAdapter() { 568bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes boolean mEndCalled = false; 569bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes 570b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 571b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(View view) { 572ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes if (!mAccessibilityManager.isEnabled()) { 573ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // Animating the children in causes Talkback to think that they're 574ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // not visible when the TYPE_WINDOW_CONTENT_CHANGED event if fired. 575ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // Fixed by skipping the animation when an accessibility manager 576ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes // is enabled 577ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes mView.animateChildrenOut(0, ANIMATION_FADE_DURATION); 578ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes } 579b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 580b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 581b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 582b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(View view) { 583e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes onViewHidden(event); 584b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 585b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }).start(); 586b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 587a577676a64e5353b8ec927117151aa6be84adf66Chris Banes Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.design_snackbar_out); 588b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR); 589b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setDuration(ANIMATION_DURATION); 590b7f9224b1495db47eb8fd813b5912250e900770aChris Banes anim.setAnimationListener(new Animation.AnimationListener() { 591b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 592b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationEnd(Animation animation) { 593e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes onViewHidden(event); 594b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 595b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 596b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 597b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationStart(Animation animation) {} 598b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 599b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 600b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public void onAnimationRepeat(Animation animation) {} 601b7f9224b1495db47eb8fd813b5912250e900770aChris Banes }); 602b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mView.startAnimation(anim); 603b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 604b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 605b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 606a89b7a8e4840e52dfda1442bcb885686680556f6Chris Banes final void hideView(@Callback.DismissEvent final int event) { 607a89b7a8e4840e52dfda1442bcb885686680556f6Chris Banes if (mView.getVisibility() != View.VISIBLE) { 608e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes onViewHidden(event); 609b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 610e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes animateViewOut(event); 611b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 612b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 613b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 614bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes private void onViewShown() { 615bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes SnackbarManager.getInstance().onShown(mManagerCallback); 616bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes if (mCallback != null) { 617bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes mCallback.onShown(this); 618bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes } 619bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes } 620bfd48d0521963754e04e407499ee9e278fe06c0fChris Banes 621e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes private void onViewHidden(int event) { 622eeea73a484fe384e6a8059e45db369cea7c247f6Chris Banes // First tell the SnackbarManager that it has been dismissed 623eeea73a484fe384e6a8059e45db369cea7c247f6Chris Banes SnackbarManager.getInstance().onDismissed(mManagerCallback); 624bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes // Now call the dismiss listener (if available) 625bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes if (mCallback != null) { 626e51e533995e445f031fc8efcce6ff9a61e7066ccChris Banes mCallback.onDismissed(this, event); 627bfae5eb86f8c5e63b33b6d36073f2230599a716bChris Banes } 628eeea73a484fe384e6a8059e45db369cea7c247f6Chris Banes // Lastly, remove the view from the parent (if attached) 629eeea73a484fe384e6a8059e45db369cea7c247f6Chris Banes final ViewParent parent = mView.getParent(); 630eeea73a484fe384e6a8059e45db369cea7c247f6Chris Banes if (parent instanceof ViewGroup) { 631eeea73a484fe384e6a8059e45db369cea7c247f6Chris Banes ((ViewGroup) parent).removeView(mView); 632eeea73a484fe384e6a8059e45db369cea7c247f6Chris Banes } 633b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 634b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 635b7f9224b1495db47eb8fd813b5912250e900770aChris Banes /** 636b7f9224b1495db47eb8fd813b5912250e900770aChris Banes * @hide 637b7f9224b1495db47eb8fd813b5912250e900770aChris Banes */ 638b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public static class SnackbarLayout extends LinearLayout { 639b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private TextView mMessageView; 6405cf1a7e04097b7e116c118cfa823a4cdb48f38a1Chris Banes private Button mActionView; 641b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 642b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private int mMaxWidth; 643b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private int mMaxInlineActionWidth; 644b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 645b7f9224b1495db47eb8fd813b5912250e900770aChris Banes interface OnLayoutChangeListener { 6465462d3e588481416a38e893bdb0f1073f82f8dccChris Banes void onLayoutChange(View view, int left, int top, int right, int bottom); 6475462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 6485462d3e588481416a38e893bdb0f1073f82f8dccChris Banes 6495462d3e588481416a38e893bdb0f1073f82f8dccChris Banes interface OnAttachStateChangeListener { 6505462d3e588481416a38e893bdb0f1073f82f8dccChris Banes void onViewAttachedToWindow(View v); 6515462d3e588481416a38e893bdb0f1073f82f8dccChris Banes void onViewDetachedFromWindow(View v); 652b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 653b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 654b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private OnLayoutChangeListener mOnLayoutChangeListener; 6555462d3e588481416a38e893bdb0f1073f82f8dccChris Banes private OnAttachStateChangeListener mOnAttachStateChangeListener; 656b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 657b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public SnackbarLayout(Context context) { 658b7f9224b1495db47eb8fd813b5912250e900770aChris Banes this(context, null); 659b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 660b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 661b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public SnackbarLayout(Context context, AttributeSet attrs) { 662b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super(context, attrs); 663b7f9224b1495db47eb8fd813b5912250e900770aChris Banes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SnackbarLayout); 664b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mMaxWidth = a.getDimensionPixelSize(R.styleable.SnackbarLayout_android_maxWidth, -1); 665b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mMaxInlineActionWidth = a.getDimensionPixelSize( 666b7f9224b1495db47eb8fd813b5912250e900770aChris Banes R.styleable.SnackbarLayout_maxActionInlineWidth, -1); 6673a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (a.hasValue(R.styleable.SnackbarLayout_elevation)) { 6683a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes ViewCompat.setElevation(this, a.getDimensionPixelSize( 6693a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes R.styleable.SnackbarLayout_elevation, 0)); 6703a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 671b7f9224b1495db47eb8fd813b5912250e900770aChris Banes a.recycle(); 672b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 673b7f9224b1495db47eb8fd813b5912250e900770aChris Banes setClickable(true); 674b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 675b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // Now inflate our content. We need to do this manually rather than using an <include> 676b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // in the layout since older versions of the Android do not inflate includes with 677b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // the correct Context. 678a577676a64e5353b8ec927117151aa6be84adf66Chris Banes LayoutInflater.from(context).inflate(R.layout.design_layout_snackbar_include, this); 6793224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes 6803224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes ViewCompat.setAccessibilityLiveRegion(this, 6813224093af46bac6f2fd5b372d5fbd56429b811c1Chris Banes ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE); 682ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes ViewCompat.setImportantForAccessibility(this, 683ed149aee7e5d78a9b5714e7b7b1cc394ca9e4af3Chris Banes ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 684b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 685b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 686b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 687b7f9224b1495db47eb8fd813b5912250e900770aChris Banes protected void onFinishInflate() { 688b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onFinishInflate(); 689b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mMessageView = (TextView) findViewById(R.id.snackbar_text); 6905cf1a7e04097b7e116c118cfa823a4cdb48f38a1Chris Banes mActionView = (Button) findViewById(R.id.snackbar_action); 691b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 692b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 693b7f9224b1495db47eb8fd813b5912250e900770aChris Banes TextView getMessageView() { 694b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mMessageView; 695b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 696b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 6975cf1a7e04097b7e116c118cfa823a4cdb48f38a1Chris Banes Button getActionView() { 698b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return mActionView; 699b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 700b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 701b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 702b7f9224b1495db47eb8fd813b5912250e900770aChris Banes protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 703b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 704b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 705b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mMaxWidth > 0 && getMeasuredWidth() > mMaxWidth) { 706b7f9224b1495db47eb8fd813b5912250e900770aChris Banes widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY); 707b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 708b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 709b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 710b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int multiLineVPadding = getResources().getDimensionPixelSize( 711a577676a64e5353b8ec927117151aa6be84adf66Chris Banes R.dimen.design_snackbar_padding_vertical_2lines); 712b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int singleLineVPadding = getResources().getDimensionPixelSize( 713a577676a64e5353b8ec927117151aa6be84adf66Chris Banes R.dimen.design_snackbar_padding_vertical); 714b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final boolean isMultiLine = mMessageView.getLayout().getLineCount() > 1; 715b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 716b7f9224b1495db47eb8fd813b5912250e900770aChris Banes boolean remeasure = false; 717b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (isMultiLine && mMaxInlineActionWidth > 0 718b7f9224b1495db47eb8fd813b5912250e900770aChris Banes && mActionView.getMeasuredWidth() > mMaxInlineActionWidth) { 719b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (updateViewsWithinLayout(VERTICAL, multiLineVPadding, 720b7f9224b1495db47eb8fd813b5912250e900770aChris Banes multiLineVPadding - singleLineVPadding)) { 721b7f9224b1495db47eb8fd813b5912250e900770aChris Banes remeasure = true; 722b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 723b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 724b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int messagePadding = isMultiLine ? multiLineVPadding : singleLineVPadding; 725b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (updateViewsWithinLayout(HORIZONTAL, messagePadding, messagePadding)) { 726b7f9224b1495db47eb8fd813b5912250e900770aChris Banes remeasure = true; 727b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 728b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 729b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 730b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (remeasure) { 731b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onMeasure(widthMeasureSpec, heightMeasureSpec); 732b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 733b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 734b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 735b7f9224b1495db47eb8fd813b5912250e900770aChris Banes void animateChildrenIn(int delay, int duration) { 736b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mMessageView, 0f); 737b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mMessageView).alpha(1f).setDuration(duration) 738b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 739b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 740b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mActionView.getVisibility() == VISIBLE) { 741b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mActionView, 0f); 742b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mActionView).alpha(1f).setDuration(duration) 743b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 744b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 745b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 746b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 747b7f9224b1495db47eb8fd813b5912250e900770aChris Banes void animateChildrenOut(int delay, int duration) { 748b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mMessageView, 1f); 749b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mMessageView).alpha(0f).setDuration(duration) 750b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 751b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 752b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mActionView.getVisibility() == VISIBLE) { 753b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setAlpha(mActionView, 1f); 754b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.animate(mActionView).alpha(0f).setDuration(duration) 755b7f9224b1495db47eb8fd813b5912250e900770aChris Banes .setStartDelay(delay).start(); 756b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 757b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 758b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 759b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 760b7f9224b1495db47eb8fd813b5912250e900770aChris Banes protected void onLayout(boolean changed, int l, int t, int r, int b) { 761b7f9224b1495db47eb8fd813b5912250e900770aChris Banes super.onLayout(changed, l, t, r, b); 762b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (changed && mOnLayoutChangeListener != null) { 763b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mOnLayoutChangeListener.onLayoutChange(this, l, t, r, b); 764b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 765b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 766b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 7675462d3e588481416a38e893bdb0f1073f82f8dccChris Banes @Override 7685462d3e588481416a38e893bdb0f1073f82f8dccChris Banes protected void onAttachedToWindow() { 7695462d3e588481416a38e893bdb0f1073f82f8dccChris Banes super.onAttachedToWindow(); 7705462d3e588481416a38e893bdb0f1073f82f8dccChris Banes if (mOnAttachStateChangeListener != null) { 7715462d3e588481416a38e893bdb0f1073f82f8dccChris Banes mOnAttachStateChangeListener.onViewAttachedToWindow(this); 7725462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 7735462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 7745462d3e588481416a38e893bdb0f1073f82f8dccChris Banes 7755462d3e588481416a38e893bdb0f1073f82f8dccChris Banes @Override 7765462d3e588481416a38e893bdb0f1073f82f8dccChris Banes protected void onDetachedFromWindow() { 7775462d3e588481416a38e893bdb0f1073f82f8dccChris Banes super.onDetachedFromWindow(); 7785462d3e588481416a38e893bdb0f1073f82f8dccChris Banes if (mOnAttachStateChangeListener != null) { 7795462d3e588481416a38e893bdb0f1073f82f8dccChris Banes mOnAttachStateChangeListener.onViewDetachedFromWindow(this); 7805462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 7815462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 7825462d3e588481416a38e893bdb0f1073f82f8dccChris Banes 783b7f9224b1495db47eb8fd813b5912250e900770aChris Banes void setOnLayoutChangeListener(OnLayoutChangeListener onLayoutChangeListener) { 784b7f9224b1495db47eb8fd813b5912250e900770aChris Banes mOnLayoutChangeListener = onLayoutChangeListener; 785b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 786b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 7875462d3e588481416a38e893bdb0f1073f82f8dccChris Banes void setOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7885462d3e588481416a38e893bdb0f1073f82f8dccChris Banes mOnAttachStateChangeListener = listener; 7895462d3e588481416a38e893bdb0f1073f82f8dccChris Banes } 7905462d3e588481416a38e893bdb0f1073f82f8dccChris Banes 791b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private boolean updateViewsWithinLayout(final int orientation, 792b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final int messagePadTop, final int messagePadBottom) { 793b7f9224b1495db47eb8fd813b5912250e900770aChris Banes boolean changed = false; 794b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (orientation != getOrientation()) { 795b7f9224b1495db47eb8fd813b5912250e900770aChris Banes setOrientation(orientation); 796b7f9224b1495db47eb8fd813b5912250e900770aChris Banes changed = true; 797b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 798b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (mMessageView.getPaddingTop() != messagePadTop 799b7f9224b1495db47eb8fd813b5912250e900770aChris Banes || mMessageView.getPaddingBottom() != messagePadBottom) { 800b7f9224b1495db47eb8fd813b5912250e900770aChris Banes updateTopBottomPadding(mMessageView, messagePadTop, messagePadBottom); 801b7f9224b1495db47eb8fd813b5912250e900770aChris Banes changed = true; 802b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 803b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return changed; 804b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 805b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 806b7f9224b1495db47eb8fd813b5912250e900770aChris Banes private static void updateTopBottomPadding(View view, int topPadding, int bottomPadding) { 807b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (ViewCompat.isPaddingRelative(view)) { 808b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.setPaddingRelative(view, 809b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.getPaddingStart(view), topPadding, 810b7f9224b1495db47eb8fd813b5912250e900770aChris Banes ViewCompat.getPaddingEnd(view), bottomPadding); 811b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } else { 812b7f9224b1495db47eb8fd813b5912250e900770aChris Banes view.setPadding(view.getPaddingLeft(), topPadding, 813b7f9224b1495db47eb8fd813b5912250e900770aChris Banes view.getPaddingRight(), bottomPadding); 814b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 815b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 816b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 817b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 818b7f9224b1495db47eb8fd813b5912250e900770aChris Banes final class Behavior extends SwipeDismissBehavior<SnackbarLayout> { 819b7f9224b1495db47eb8fd813b5912250e900770aChris Banes @Override 82002751b16719af2e3f8212f93c001da1b0566b1b5Chris Banes public boolean canSwipeDismissView(View child) { 82102751b16719af2e3f8212f93c001da1b0566b1b5Chris Banes return child instanceof SnackbarLayout; 82202751b16719af2e3f8212f93c001da1b0566b1b5Chris Banes } 82302751b16719af2e3f8212f93c001da1b0566b1b5Chris Banes 82402751b16719af2e3f8212f93c001da1b0566b1b5Chris Banes @Override 825b7f9224b1495db47eb8fd813b5912250e900770aChris Banes public boolean onInterceptTouchEvent(CoordinatorLayout parent, SnackbarLayout child, 826b7f9224b1495db47eb8fd813b5912250e900770aChris Banes MotionEvent event) { 827b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // We want to make sure that we disable any Snackbar timeouts if the user is 828b7f9224b1495db47eb8fd813b5912250e900770aChris Banes // currently touching the Snackbar. We restore the timeout when complete 829b7f9224b1495db47eb8fd813b5912250e900770aChris Banes if (parent.isPointInChildBounds(child, (int) event.getX(), (int) event.getY())) { 830b7f9224b1495db47eb8fd813b5912250e900770aChris Banes switch (event.getActionMasked()) { 831b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MotionEvent.ACTION_DOWN: 832b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().cancelTimeout(mManagerCallback); 833b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 834b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MotionEvent.ACTION_UP: 835b7f9224b1495db47eb8fd813b5912250e900770aChris Banes case MotionEvent.ACTION_CANCEL: 836b7f9224b1495db47eb8fd813b5912250e900770aChris Banes SnackbarManager.getInstance().restoreTimeout(mManagerCallback); 837b7f9224b1495db47eb8fd813b5912250e900770aChris Banes break; 838b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 839b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 840b7f9224b1495db47eb8fd813b5912250e900770aChris Banes 841b7f9224b1495db47eb8fd813b5912250e900770aChris Banes return super.onInterceptTouchEvent(parent, child, event); 842b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 843b7f9224b1495db47eb8fd813b5912250e900770aChris Banes } 844b7f9224b1495db47eb8fd813b5912250e900770aChris Banes} 845