Merge "MediaRouter: Adjust icon size properly for orientation change" into mnc-ub-dev
diff --git a/design/api/current.txt b/design/api/current.txt
index 39d63ec..5ec5c54 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -204,7 +204,6 @@
ctor public FloatingActionButton.Behavior();
method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
- method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
}
@@ -262,6 +261,7 @@
method public int getDuration();
method public android.view.View getView();
method public boolean isShown();
+ method public boolean isShownOrQueued();
method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index a8f1446..e997527 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -161,8 +161,6 @@
mBackgroundTintMode, mRippleColor, mBorderWidth);
mImpl.setElevation(elevation);
mImpl.setPressedTranslationZ(pressedTranslationZ);
-
- setClickable(true);
}
@Override
@@ -389,6 +387,7 @@
// because we can use view translation properties which greatly simplifies the code.
private static final boolean SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11;
+ private float mFabTranslationY;
private Rect mTmpRect;
@Override
@@ -411,24 +410,6 @@
return false;
}
- @Override
- public void onDependentViewRemoved(CoordinatorLayout parent, FloatingActionButton child,
- View dependency) {
- if (dependency instanceof Snackbar.SnackbarLayout) {
- // If the removed view is a SnackbarLayout, we will animate back to our normal
- // position
- if (ViewCompat.getTranslationY(child) != 0f) {
- ViewCompat.animate(child)
- .translationY(0f)
- .scaleX(1f)
- .scaleY(1f)
- .alpha(1f)
- .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
- .setListener(null);
- }
- }
- }
-
private boolean updateFabVisibility(CoordinatorLayout parent,
AppBarLayout appBarLayout, FloatingActionButton child) {
final CoordinatorLayout.LayoutParams lp =
@@ -463,8 +444,32 @@
return;
}
- final float translationY = getFabTranslationYForSnackbar(parent, fab);
- ViewCompat.setTranslationY(fab, translationY);
+ final float targetTransY = getFabTranslationYForSnackbar(parent, fab);
+ if (mFabTranslationY == targetTransY) {
+ // We're already at (or currently animating to) the target value, return...
+ return;
+ }
+
+ mFabTranslationY = targetTransY;
+ final float currentTransY = ViewCompat.getTranslationY(fab);
+ final float dy = currentTransY - targetTransY;
+
+ if (Math.abs(dy) > (fab.getHeight() * 0.667f)) {
+ // If the FAB will be travelling by more than 2/3 of it's height, let's animate
+ // it instead
+ ViewCompat.animate(fab)
+ .translationY(targetTransY)
+ .scaleX(1f)
+ .scaleY(1f)
+ .alpha(1f)
+ .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
+ .setListener(null);
+ } else {
+ // Make sure that any current animation is cancelled
+ ViewCompat.animate(fab).cancel();
+ // Now update the translation Y
+ ViewCompat.setTranslationY(fab, targetTransY);
+ }
}
private float getFabTranslationYForSnackbar(CoordinatorLayout parent,
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index 0fccafe..af300f1 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -169,20 +169,21 @@
});
}
- private final ViewGroup mParent;
+ private final ViewGroup mTargetParent;
private final Context mContext;
private final SnackbarLayout mView;
private int mDuration;
private Callback mCallback;
private Snackbar(ViewGroup parent) {
- mParent = parent;
+ mTargetParent = parent;
mContext = parent.getContext();
ThemeUtils.checkAppCompatTheme(mContext);
LayoutInflater inflater = LayoutInflater.from(mContext);
- mView = (SnackbarLayout) inflater.inflate(R.layout.design_layout_snackbar, mParent, false);
+ mView = (SnackbarLayout) inflater.inflate(
+ R.layout.design_layout_snackbar, mTargetParent, false);
}
/**
@@ -403,10 +404,18 @@
}
/**
- * Return whether this Snackbar is currently being shown.
+ * Return whether this {@link Snackbar} is currently being shown.
*/
public boolean isShown() {
- return mView.isShown();
+ return SnackbarManager.getInstance().isCurrent(mManagerCallback);
+ }
+
+ /**
+ * Returns whether this {@link Snackbar} is currently being shown, or is queued to be
+ * shown next.
+ */
+ public boolean isShownOrQueued() {
+ return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback);
}
private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
@@ -456,9 +465,30 @@
((CoordinatorLayout.LayoutParams) lp).setBehavior(behavior);
}
- mParent.addView(mView);
+ mTargetParent.addView(mView);
}
+ mView.setOnAttachStateChangeListener(new SnackbarLayout.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {}
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (isShownOrQueued()) {
+ // If we haven't already been dismissed then this event is coming from a
+ // non-user initiated action. Hence we need to make sure that we callback
+ // and keep our state up to date. We need to post the call since removeView()
+ // will call through to onDetachedFromWindow and thus overflow.
+ sHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onViewHidden(Callback.DISMISS_EVENT_MANUAL);
+ }
+ });
+ }
+ }
+ });
+
if (ViewCompat.isLaidOut(mView)) {
// If the view is already laid out, animate it now
animateViewIn();
@@ -563,8 +593,11 @@
}
private void onViewHidden(int event) {
- // First remove the view from the parent
- mParent.removeView(mView);
+ // First remove the view from the parent (if attached)
+ final ViewParent parent = mView.getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(mView);
+ }
// Now call the dismiss listener (if available)
if (mCallback != null) {
mCallback.onDismissed(this, event);
@@ -602,10 +635,16 @@
private int mMaxInlineActionWidth;
interface OnLayoutChangeListener {
- public void onLayoutChange(View view, int left, int top, int right, int bottom);
+ void onLayoutChange(View view, int left, int top, int right, int bottom);
+ }
+
+ interface OnAttachStateChangeListener {
+ void onViewAttachedToWindow(View v);
+ void onViewDetachedFromWindow(View v);
}
private OnLayoutChangeListener mOnLayoutChangeListener;
+ private OnAttachStateChangeListener mOnAttachStateChangeListener;
public SnackbarLayout(Context context) {
this(context, null);
@@ -712,10 +751,30 @@
}
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mOnAttachStateChangeListener != null) {
+ mOnAttachStateChangeListener.onViewAttachedToWindow(this);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mOnAttachStateChangeListener != null) {
+ mOnAttachStateChangeListener.onViewDetachedFromWindow(this);
+ }
+ }
+
void setOnLayoutChangeListener(OnLayoutChangeListener onLayoutChangeListener) {
mOnLayoutChangeListener = onLayoutChangeListener;
}
+ void setOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
+ mOnAttachStateChangeListener = listener;
+ }
+
private boolean updateViewsWithinLayout(final int orientation,
final int messagePadTop, final int messagePadBottom) {
boolean changed = false;
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
index 253ee92..be2f024 100644
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ b/design/src/android/support/design/widget/SnackbarManager.java
@@ -69,7 +69,7 @@
public void show(int duration, Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
// Means that the callback is already in the queue. We'll just update the duration
mCurrentSnackbar.duration = duration;
@@ -78,7 +78,7 @@
mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
scheduleTimeoutLocked(mCurrentSnackbar);
return;
- } else if (isNextSnackbar(callback)) {
+ } else if (isNextSnackbarLocked(callback)) {
// We'll just update the duration
mNextSnackbar.duration = duration;
} else {
@@ -101,9 +101,9 @@
public void dismiss(Callback callback, int event) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
cancelSnackbarLocked(mCurrentSnackbar, event);
- } else if (isNextSnackbar(callback)) {
+ } else if (isNextSnackbarLocked(callback)) {
cancelSnackbarLocked(mNextSnackbar, event);
}
}
@@ -115,7 +115,7 @@
*/
public void onDismissed(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
// If the callback is from a Snackbar currently show, remove it and show a new one
mCurrentSnackbar = null;
if (mNextSnackbar != null) {
@@ -131,7 +131,7 @@
*/
public void onShown(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
scheduleTimeoutLocked(mCurrentSnackbar);
}
}
@@ -139,7 +139,7 @@
public void cancelTimeout(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
}
}
@@ -147,12 +147,24 @@
public void restoreTimeout(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
scheduleTimeoutLocked(mCurrentSnackbar);
}
}
}
+ public boolean isCurrent(Callback callback) {
+ synchronized (mLock) {
+ return isCurrentSnackbarLocked(callback);
+ }
+ }
+
+ public boolean isCurrentOrNext(Callback callback) {
+ synchronized (mLock) {
+ return isCurrentSnackbarLocked(callback) || isNextSnackbarLocked(callback);
+ }
+ }
+
private static class SnackbarRecord {
private final WeakReference<Callback> callback;
private int duration;
@@ -191,11 +203,11 @@
return false;
}
- private boolean isCurrentSnackbar(Callback callback) {
+ private boolean isCurrentSnackbarLocked(Callback callback) {
return mCurrentSnackbar != null && mCurrentSnackbar.isSnackbar(callback);
}
- private boolean isNextSnackbar(Callback callback) {
+ private boolean isNextSnackbarLocked(Callback callback) {
return mNextSnackbar != null && mNextSnackbar.isSnackbar(callback);
}