Merge "Allow setting the Tab Indicator at runtime" into lmp-mr1-ub-dev
diff --git a/design/api/current.txt b/design/api/current.txt
index fd25afc..fdc7968 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -219,6 +219,7 @@
method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
method public android.support.design.widget.Snackbar setActionTextColor(int);
+ method public void setCallback(android.support.design.widget.Snackbar.Callback);
method public android.support.design.widget.Snackbar setDuration(int);
method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
method public android.support.design.widget.Snackbar setText(int);
@@ -227,6 +228,12 @@
field public static final int LENGTH_SHORT = -1; // 0xffffffff
}
+ public static abstract class Snackbar.Callback {
+ ctor public Snackbar.Callback();
+ method public void onDismissed(android.support.design.widget.Snackbar);
+ method public void onShown(android.support.design.widget.Snackbar);
+ }
+
public class SwipeDismissBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
ctor public SwipeDismissBehavior();
method public int getDragState();
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index f84b567..55a7594 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -51,6 +51,7 @@
public class NavigationMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
private static final String STATE_HIERARCHY = "android:menu:list";
+ private static final String STATE_ADAPTER = "android:menu:adapter";
private NavigationMenuView mMenuView;
private LinearLayout mHeader;
@@ -155,11 +156,14 @@
@Override
public Parcelable onSaveInstanceState() {
Bundle state = new Bundle();
- SparseArray<Parcelable> hierarchy = new SparseArray<>();
if (mMenuView != null) {
+ SparseArray<Parcelable> hierarchy = new SparseArray<>();
mMenuView.saveHierarchyState(hierarchy);
+ state.putSparseParcelableArray(STATE_HIERARCHY, hierarchy);
}
- state.putSparseParcelableArray(STATE_HIERARCHY, hierarchy);
+ if (mAdapter != null) {
+ state.putBundle(STATE_ADAPTER, mAdapter.createInstanceState());
+ }
return state;
}
@@ -170,6 +174,10 @@
if (hierarchy != null) {
mMenuView.restoreHierarchyState(hierarchy);
}
+ Bundle adapterState = state.getBundle(STATE_ADAPTER);
+ if (adapterState != null) {
+ mAdapter.restoreInstanceState(adapterState);
+ }
}
@Override
@@ -226,12 +234,16 @@
}
private class NavigationMenuAdapter extends BaseAdapter {
+
+ private static final String STATE_CHECKED_ITEMS = "android:menu:checked";
+
private static final int VIEW_TYPE_NORMAL = 0;
private static final int VIEW_TYPE_SUBHEADER = 1;
private static final int VIEW_TYPE_SEPARATOR = 2;
private final ArrayList<NavigationMenuItem> mItems = new ArrayList<>();
private ColorDrawable mTransparentIcon;
+ private boolean mUpdateSuspended;
NavigationMenuAdapter() {
prepareMenuItems();
@@ -326,6 +338,9 @@
* while inserting separators between items when necessary.
*/
private void prepareMenuItems() {
+ if (mUpdateSuspended) {
+ return;
+ }
mItems.clear();
int currentGroupId = -1;
int currentGroupStart = 0;
@@ -388,6 +403,35 @@
}
}
}
+
+ public Bundle createInstanceState() {
+ Bundle state = new Bundle();
+ ArrayList<Integer> checkedItems = new ArrayList<>();
+ for (NavigationMenuItem item : mItems) {
+ MenuItemImpl menuItem = item.getMenuItem();
+ if (menuItem != null && menuItem.isChecked()) {
+ checkedItems.add(menuItem.getItemId());
+ }
+ }
+ state.putIntegerArrayList(STATE_CHECKED_ITEMS, checkedItems);
+ return state;
+ }
+
+ public void restoreInstanceState(Bundle state) {
+ ArrayList<Integer> checkedItems = state.getIntegerArrayList(STATE_CHECKED_ITEMS);
+ if (checkedItems != null) {
+ mUpdateSuspended = true;
+ for (NavigationMenuItem item : mItems) {
+ MenuItemImpl menuItem = item.getMenuItem();
+ if (menuItem != null && checkedItems.contains(menuItem.getItemId())) {
+ menuItem.setChecked(true);
+ }
+ }
+ mUpdateSuspended = false;
+ prepareMenuItems();
+ }
+ }
+
}
/**
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 328fcac..437e2d1 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -24,6 +24,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.support.design.R;
+import android.support.v4.text.TextDirectionHeuristicsCompat;
import android.support.v4.view.ViewCompat;
import android.text.TextPaint;
import android.text.TextUtils;
@@ -66,6 +67,7 @@
private CharSequence mText;
private CharSequence mTextToDraw;
private float mTextWidth;
+ private boolean mIsRtl;
private boolean mUseTexture;
private Bitmap mExpandedTitleTexture;
@@ -282,8 +284,7 @@
final int saveCount = canvas.save();
if (mTextToDraw != null) {
- final boolean isRtl = ViewCompat.getLayoutDirection(mView)
- == ViewCompat.LAYOUT_DIRECTION_RTL;
+ final boolean isRtl = mIsRtl;
float x = isRtl ? mCurrentRight : mCurrentLeft;
float y = mCurrentTop;
@@ -333,6 +334,14 @@
canvas.restoreToCount(saveCount);
}
+ private boolean calculateIsRtl(CharSequence text) {
+ final boolean defaultIsRtl = ViewCompat.getLayoutDirection(mView)
+ == ViewCompat.LAYOUT_DIRECTION_RTL;
+ return (defaultIsRtl
+ ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL
+ : TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR).isRtl(text, 0, text.length());
+ }
+
private void setInterpolatedTextSize(final float textSize) {
if (mText == null) return;
@@ -371,6 +380,7 @@
if (mTextToDraw == null || !mTextToDraw.equals(title)) {
mTextToDraw = title;
}
+ mIsRtl = calculateIsRtl(mTextToDraw);
mTextWidth = mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length());
}
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index 80c24f1..f3df4f9 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -58,10 +58,41 @@
* <p>
* Snackbars can contain an action which is set via
* {@link #setAction(CharSequence, android.view.View.OnClickListener)}.
+ * <p>
+ * To be notified when a snackbar has been shown or dismissed, you can provide a {@link Callback}
+ * via {@link #setCallback(Callback)}.</p>
*/
public class Snackbar {
/**
+ * Callback class for {@link Snackbar} instances.
+ *
+ * @see Snackbar#setCallback(Callback)
+ */
+ public static abstract class Callback {
+ /**
+ * Called when the given {@link Snackbar} has been dismissed, either through a time-out,
+ * having been manually dismissed, or an action being clicked.
+ *
+ * @param snackbar The snackbar which has been dismissed.
+ * @see Snackbar#dismiss()
+ */
+ public void onDismissed(Snackbar snackbar) {
+ // empty
+ }
+
+ /**
+ * Called when the given {@link Snackbar} is visible.
+ *
+ * @param snackbar The snackbar which is now visible.
+ * @see Snackbar#show()
+ */
+ public void onShown(Snackbar snackbar) {
+ // empty
+ }
+ }
+
+ /**
* @hide
*/
@IntDef({LENGTH_SHORT, LENGTH_LONG})
@@ -110,6 +141,7 @@
private final Context mContext;
private final SnackbarLayout mView;
private int mDuration;
+ private Callback mCallback;
Snackbar(ViewGroup parent) {
mParent = parent;
@@ -314,6 +346,13 @@
SnackbarManager.getInstance().dismiss(mManagerCallback);
}
+ /**
+ * Set a callback to be called when this the visibility of this {@link Snackbar} changes.
+ */
+ public void setCallback(Callback callback) {
+ mCallback = callback;
+ }
+
private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
@Override
public void show() {
@@ -394,6 +433,9 @@
@Override
public void onAnimationEnd(View view) {
+ if (mCallback != null) {
+ mCallback.onShown(Snackbar.this);
+ }
SnackbarManager.getInstance().onShown(mManagerCallback);
}
}).start();
@@ -404,6 +446,9 @@
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
+ if (mCallback != null) {
+ mCallback.onShown(Snackbar.this);
+ }
SnackbarManager.getInstance().onShown(mManagerCallback);
}
@@ -464,7 +509,11 @@
private void onViewHidden() {
// First remove the view from the parent
mParent.removeView(mView);
- // Now, tell the SnackbarManager that it has been dismissed
+ // Now call the dismiss listener (if available)
+ if (mCallback != null) {
+ mCallback.onDismissed(this);
+ }
+ // Finally, tell the SnackbarManager that it has been dismissed
SnackbarManager.getInstance().onDismissed(mManagerCallback);
}
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 230f530..6282146 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -326,12 +326,12 @@
mCollapsingTextHelper.onLayout(changed, left, top, right, bottom);
if (mEditText != null) {
- final int l = mEditText.getLeft() + mEditText.getPaddingLeft();
- final int r = mEditText.getRight() - mEditText.getPaddingRight();
+ final int l = mEditText.getLeft() + mEditText.getCompoundPaddingLeft();
+ final int r = mEditText.getRight() - mEditText.getCompoundPaddingRight();
mCollapsingTextHelper.setExpandedBounds(l,
- mEditText.getTop() + mEditText.getPaddingTop(),
- r, mEditText.getBottom() - mEditText.getPaddingBottom());
+ mEditText.getTop() + mEditText.getCompoundPaddingTop(),
+ r, mEditText.getBottom() - mEditText.getCompoundPaddingBottom());
// Set the collapsed bounds to be the the full height (minus padding) to match the
// EditText's editable area
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
index 557bb66..9355502 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
@@ -493,7 +493,7 @@
int r = modifyWordWidth(Color.red(color), 8, QUANTIZE_WORD_WIDTH);
int g = modifyWordWidth(Color.green(color), 8, QUANTIZE_WORD_WIDTH);
int b = modifyWordWidth(Color.blue(color), 8, QUANTIZE_WORD_WIDTH);
- return r << (QUANTIZE_WORD_WIDTH * 2) | g << QUANTIZE_WORD_WIDTH | b;
+ return r << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH) | g << QUANTIZE_WORD_WIDTH | b;
}
/**
@@ -533,9 +533,8 @@
private static int modifyWordWidth(int value, int currentWidth, int targetWidth) {
final int newValue;
if (targetWidth > currentWidth) {
- // If we're approximating up in word width, we'll use scaling to approximate the
- // new value
- newValue = value * ((1 << targetWidth) - 1) / ((1 << currentWidth) - 1);
+ // If we're approximating up in word width, we'll shift up
+ newValue = value << (targetWidth - currentWidth);
} else {
// Else, we will just shift and keep the MSB
newValue = value >> (currentWidth - targetWidth);
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 30a147a..d795b18 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -5684,7 +5684,7 @@
* normal layout operation during {@link #onLayoutChildren(Recycler, State)}, the
* RecyclerView will have enough information to run those animations in a simple
* way. For example, the default ItemAnimator, {@link DefaultItemAnimator}, will
- * simple fade views in and out, whether they are actuall added/removed or whether
+ * simply fade views in and out, whether they are actually added/removed or whether
* they are moved on or off the screen due to other add/remove operations.
*
* <p>A LayoutManager wanting a better item animation experience, where items can be