Remove all the extra accessor methods added by javac in support-vector-drawable.
am: 8fbfb9b792

Change-Id: I8985df2e8fff9b1163fdfa6ee074e792dacf0af3
diff --git a/annotations/src/android/support/annotation/RestrictTo.java b/annotations/src/android/support/annotation/RestrictTo.java
new file mode 100644
index 0000000..65c8ba0
--- /dev/null
+++ b/annotations/src/android/support/annotation/RestrictTo.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+/**
+ * Denotes that the annotated element should only be accessed from within a
+ * specific scope (as defined by {@link Scope}).
+ * <p>
+ * Example of restricting usage within a library (based on gradle group ID):
+ * <pre><code>
+ *   &#64;RestrictTo(GROUP_ID)
+ *   public void resetPaddingToInitialValues() { ...
+ * </code></pre>
+ * Example of restricting usage to tests:
+ * <pre><code>
+ *   &#64;RestrictScope(TESTS)
+ *   public abstract int getUserId();
+ * </code></pre>
+ * Example of restricting usage to subclasses:
+ * <pre><code>
+ *   &#64;RestrictScope(SUBCLASSES)
+ *   public void onDrawForeground(Canvas canvas) { ...
+ * </code></pre>
+ */
+@Retention(CLASS)
+@Target({ANNOTATION_TYPE,TYPE,METHOD,CONSTRUCTOR,FIELD,PACKAGE})
+public @interface RestrictTo {
+
+    /**
+     * The scope to which usage should be restricted.
+     */
+    Scope[] value();
+
+    enum Scope {
+        /**
+         * Restrict usage to code within the same group ID (based on gradle
+         * group ID).
+         */
+        GROUP_ID,
+
+        /**
+         * Restrict usage to tests.
+         */
+        TESTS,
+
+        /**
+         * Restrict usage to subclasses of the enclosing class.
+         * <p>
+         * <strong>Note:</strong> This scope should not be used to annotate
+         * packages.
+         */
+        SUBCLASSES,
+    }
+}
diff --git a/api/current.txt b/api/current.txt
index bd2ea01..b2101c7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -312,6 +312,26 @@
     method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
   }
 
+  public class BottomNavigationView extends android.widget.FrameLayout {
+    ctor public BottomNavigationView(android.content.Context);
+    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
+    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
+    method public int getItemBackgroundResource();
+    method public android.content.res.ColorStateList getItemIconTintList();
+    method public android.content.res.ColorStateList getItemTextColor();
+    method public int getMaxItemCount();
+    method public android.view.Menu getMenu();
+    method public void inflateMenu(int);
+    method public void setItemBackgroundResource(int);
+    method public void setItemIconTintList(android.content.res.ColorStateList);
+    method public void setItemTextColor(android.content.res.ColorStateList);
+    method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
+  }
+
+  public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
+    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+  }
+
   public class BottomSheetBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
     ctor public BottomSheetBehavior();
     ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
@@ -504,6 +524,7 @@
     method public float getCompatElevation();
     method public android.graphics.drawable.Drawable getContentBackground();
     method public boolean getContentRect(android.graphics.Rect);
+    method public int getRippleColor();
     method public int getSize();
     method public boolean getUseCompatPadding();
     method public void hide();
@@ -988,6 +1009,7 @@
 package android.support.v13.app {
 
   public class ActivityCompat extends android.support.v4.app.ActivityCompat {
+    ctor protected ActivityCompat();
     method public static android.support.v13.view.DragAndDropPermissionsCompat requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
   }
 
@@ -1054,6 +1076,38 @@
 
 }
 
+package android.support.v13.view.inputmethod {
+
+  public final class EditorInfoCompat {
+    ctor public EditorInfoCompat();
+    method public static java.lang.String[] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+    method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, java.lang.String[]);
+  }
+
+  public final class InputConnectionCompat {
+    ctor public InputConnectionCompat();
+    method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
+    method public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+    field public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
+  }
+
+  public static abstract interface InputConnectionCompat.OnCommitContentListener {
+    method public abstract boolean onCommitContent(android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
+  }
+
+  public final class InputContentInfoCompat {
+    ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri getLinkUri();
+    method public void releasePermission();
+    method public void requestPermission();
+    method public java.lang.Object unwrap();
+    method public static android.support.v13.view.inputmethod.InputContentInfoCompat wrap(java.lang.Object);
+  }
+
+}
+
 package android.support.v14.preference {
 
   public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
@@ -3665,10 +3719,10 @@
   }
 
   public class ActivityCompat extends android.support.v4.content.ContextCompat {
-    ctor public deprecated ActivityCompat();
+    ctor protected ActivityCompat();
     method public static void finishAffinity(android.app.Activity);
     method public static void finishAfterTransition(android.app.Activity);
-    method public deprecated android.net.Uri getReferrer(android.app.Activity);
+    method public static android.net.Uri getReferrer(android.app.Activity);
     method public static boolean invalidateOptionsMenu(android.app.Activity);
     method public static void postponeEnterTransition(android.app.Activity);
     method public static void requestPermissions(android.app.Activity, java.lang.String[], int);
@@ -4614,7 +4668,7 @@
   }
 
   public class ContextCompat {
-    ctor public deprecated ContextCompat();
+    ctor protected ContextCompat();
     method public static int checkSelfPermission(android.content.Context, java.lang.String);
     method public static android.content.Context createDeviceProtectedStorageContext(android.content.Context);
     method public static java.io.File getCodeCacheDir(android.content.Context);
@@ -5489,7 +5543,11 @@
 
   public final class ConnectivityManagerCompat {
     method public static android.net.NetworkInfo getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+    method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
     method public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
   }
 
   public final class TrafficStatsCompat {
@@ -6259,6 +6317,7 @@
     method public static android.content.res.ColorStateList getBackgroundTintList(android.view.View);
     method public static android.graphics.PorterDuff.Mode getBackgroundTintMode(android.view.View);
     method public static android.graphics.Rect getClipBounds(android.view.View);
+    method public static android.view.Display getDisplay(android.view.View);
     method public static float getElevation(android.view.View);
     method public static boolean getFitsSystemWindows(android.view.View);
     method public static int getImportantForAccessibility(android.view.View);
@@ -6322,6 +6381,7 @@
     method public static void setAccessibilityLiveRegion(android.view.View, int);
     method public static void setActivated(android.view.View, boolean);
     method public static void setAlpha(android.view.View, float);
+    method public static void setBackground(android.view.View, android.graphics.drawable.Drawable);
     method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList);
     method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode);
     method public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup, boolean);
@@ -6439,6 +6499,7 @@
     method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
     method public void setPageMarginDrawable(int);
     method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer, int);
     field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
     field public static final int SCROLL_STATE_IDLE = 0; // 0x0
     field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
@@ -7377,6 +7438,8 @@
     ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
     method public boolean canChildScrollUp();
     method public int getProgressCircleDiameter();
+    method public int getProgressViewEndOffset();
+    method public int getProgressViewStartOffset();
     method public boolean isRefreshing();
     method protected void onLayout(boolean, int, int, int, int);
     method public void onMeasure(int, int);
@@ -7875,6 +7938,14 @@
     ctor public NotificationCompat.Builder(android.content.Context);
   }
 
+  public static class NotificationCompat.DecoratedCustomViewStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.DecoratedCustomViewStyle();
+  }
+
+  public static class NotificationCompat.DecoratedMediaCustomViewStyle extends android.support.v7.app.NotificationCompat.MediaStyle {
+    ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+  }
+
   public static class NotificationCompat.MediaStyle extends android.support.v4.app.NotificationCompat.Style {
     ctor public NotificationCompat.MediaStyle();
     ctor public NotificationCompat.MediaStyle(android.support.v4.app.NotificationCompat.Builder);
@@ -9076,6 +9147,14 @@
     method public void runPendingAnimations();
   }
 
+  public class DividerItemDecoration extends android.support.v7.widget.RecyclerView.ItemDecoration {
+    ctor public DividerItemDecoration(android.content.Context, int);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
   public class GridLayout extends android.view.ViewGroup {
     ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
     ctor public GridLayout(android.content.Context, android.util.AttributeSet);
@@ -9434,6 +9513,7 @@
     method public deprecated int getChildPosition(android.view.View);
     method public android.support.v7.widget.RecyclerView.ViewHolder getChildViewHolder(android.view.View);
     method public android.support.v7.widget.RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate();
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
     method public android.support.v7.widget.RecyclerView.ItemAnimator getItemAnimator();
     method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
     method public int getMaxFlingVelocity();
@@ -9680,6 +9760,7 @@
     method public boolean isAttachedToWindow();
     method public boolean isAutoMeasureEnabled();
     method public boolean isFocused();
+    method public final boolean isItemPrefetchEnabled();
     method public boolean isLayoutHierarchical(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
     method public boolean isMeasurementCacheEnabled();
     method public boolean isSmoothScrolling();
@@ -9733,6 +9814,7 @@
     method public void scrollToPosition(int);
     method public int scrollVerticallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
     method public void setAutoMeasureEnabled(boolean);
+    method public final void setItemPrefetchEnabled(boolean);
     method public void setMeasuredDimension(android.graphics.Rect, int, int);
     method public void setMeasuredDimension(int, int);
     method public void setMeasurementCacheEnabled(boolean);
diff --git a/api/removed.txt b/api/removed.txt
index 7dadbb7..401cf00 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,12 +1,3 @@
-package android.support.v4.content {
-
-  public class ContextCompat {
-    method public static deprecated android.content.Context createDeviceEncryptedStorageContext(android.content.Context);
-    method public static deprecated boolean isDeviceEncryptedStorage(android.content.Context);
-  }
-
-}
-
 package android.support.v4.os {
 
   public class UserManagerCompat {
diff --git a/build.gradle b/build.gradle
index 4cc4f89..8768f56 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,8 +30,8 @@
     doclava project(':doclava')
 }
 
-ext.supportVersion = '24.2.1'
-ext.extraVersion = 37
+ext.supportVersion = '25.0.0-SNAPSHOT'
+ext.extraVersion = 36
 ext.supportRepoOut = ''
 ext.buildToolsVersion = '23.0.2'
 ext.buildNumber = Integer.toString(ext.extraVersion)
@@ -224,8 +224,16 @@
     def sourceSet = subProject.sourceSets.create(name)
     sourceSet.java.srcDirs = [folder]
 
-    def configName = sourceSet.getCompileConfigurationName()
+    // The Android gradle plugin doesn't touch Java sub-tasks, so we need to
+    // manually set the Java task's boot classpath to the correct Android SDK.
+    def compileJavaTaskName = sourceSet.getCompileJavaTaskName();
+    def compileJavaOptions = subProject.tasks."${compileJavaTaskName}".options
+    compileJavaOptions.bootClasspath = getAndroidPrebuilt(apiLevel)
 
+    // Useful for cleaning up compiler warnings...
+    //compileJavaOptions.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+
+    def configName = sourceSet.getCompileConfigurationName()
     subProject.getDependencies().add(configName, getAndroidPrebuilt(apiLevel))
     if (previousSource != null) {
         setupDependencies(subProject, configName, previousSource)
diff --git a/buildSrc/studioCompat.gradle b/buildSrc/studioCompat.gradle
index 123eec1..1712bda 100644
--- a/buildSrc/studioCompat.gradle
+++ b/buildSrc/studioCompat.gradle
@@ -106,7 +106,8 @@
                 new ApiModule("ics", 14),
                 new ApiModule("ics-mr1", 15),
                 new ApiModule("api23", 23),
-                new ApiModule("api24", ApiModule.CURRENT)
+                new ApiModule("api24", 24),
+                new ApiModule("api25", ApiModule.CURRENT)
             ],
             dependencies : [":support-v4"],
             folder : "v13",
diff --git a/compat/api21/android/support/v4/app/ActivityCompat21.java b/compat/api21/android/support/v4/app/ActivityCompatApi21.java
similarity index 99%
rename from compat/api21/android/support/v4/app/ActivityCompat21.java
rename to compat/api21/android/support/v4/app/ActivityCompatApi21.java
index 2e6de1e..51888d4 100644
--- a/compat/api21/android/support/v4/app/ActivityCompat21.java
+++ b/compat/api21/android/support/v4/app/ActivityCompatApi21.java
@@ -30,7 +30,7 @@
 import java.util.List;
 import java.util.Map;
 
-class ActivityCompat21 {
+class ActivityCompatApi21 {
 
     public static void setMediaController(Activity activity, Object mediaControllerObj) {
         activity.setMediaController((MediaController) mediaControllerObj);
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/compat/api22/android/support/v4/app/ActivityCompatApi22.java
similarity index 96%
rename from compat/api22/android/support/v4/app/ActivityCompat22.java
rename to compat/api22/android/support/v4/app/ActivityCompatApi22.java
index 3946f1d..c56d490 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/compat/api22/android/support/v4/app/ActivityCompatApi22.java
@@ -19,7 +19,7 @@
 import android.app.Activity;
 import android.net.Uri;
 
-class ActivityCompat22 {
+class ActivityCompatApi22 {
     public static Uri getReferrer(Activity activity) {
         return activity.getReferrer();
     }
diff --git a/compat/api23/android/support/v4/app/ActivityCompatApi23.java b/compat/api23/android/support/v4/app/ActivityCompatApi23.java
index 5ed84df..ab46058 100644
--- a/compat/api23/android/support/v4/app/ActivityCompatApi23.java
+++ b/compat/api23/android/support/v4/app/ActivityCompatApi23.java
@@ -69,7 +69,7 @@
     }
 
     public abstract static class SharedElementCallback23
-            extends ActivityCompat21.SharedElementCallback21 {
+            extends ActivityCompatApi21.SharedElementCallback21 {
         public abstract void onSharedElementsArrived(List<String> sharedElementNames,
                 List<View> sharedElements, OnSharedElementsReadyListenerBridge listener);
     }
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
similarity index 60%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
index 3946f1d..5e0edf9 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-package android.support.v4.app;
+package android.support.v4.net;
 
-import android.app.Activity;
-import android.net.Uri;
+import android.net.ConnectivityManager;
 
-class ActivityCompat22 {
-    public static Uri getReferrer(Activity activity) {
-        return activity.getReferrer();
+/**
+ * Implementation of ConnectivityManagerCompat that can use API 24 APIs.
+ */
+class ConnectivityManagerCompatApi24 {
+    public static int getRestrictBackgroundStatus(ConnectivityManager cm) {
+        return cm.getRestrictBackgroundStatus();
     }
 }
diff --git a/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorBase.java b/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorBase.java
new file mode 100644
index 0000000..afac122
--- /dev/null
+++ b/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorBase.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.os;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+class ParcelableCompatCreatorBase<T> implements Parcelable.Creator<T> {
+    final ParcelableCompatCreatorCallbacks<T> mCallbacks;
+
+    public ParcelableCompatCreatorBase(ParcelableCompatCreatorCallbacks<T> callbacks) {
+        mCallbacks = callbacks;
+    }
+
+    @Override
+    public T createFromParcel(Parcel source) {
+        return mCallbacks.createFromParcel(source, null);
+    }
+
+    @Override
+    public T[] newArray(int size) {
+        return mCallbacks.newArray(size);
+    }
+}
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorCallbacks.java b/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
similarity index 100%
rename from compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
rename to compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
diff --git a/compat/gingerbread/android/support/v4/view/ViewCompatBase.java b/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
index f4e113e..e7882bd 100644
--- a/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
+++ b/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
@@ -16,10 +16,13 @@
 
 package android.support.v4.view;
 
+import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
+import android.view.Display;
 import android.view.View;
 import android.view.ViewParent;
+import android.view.WindowManager;
 
 import java.lang.reflect.Field;
 
@@ -149,4 +152,14 @@
             }
         }
     }
+
+    static Display getDisplay(View view) {
+        if (isAttachedToWindow(view)) {
+            final WindowManager wm = (WindowManager) view.getContext().getSystemService(
+                    Context.WINDOW_SERVICE);
+            return wm.getDefaultDisplay();
+        }
+        return null;
+    }
+
 }
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorHoneycombMR2.java b/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorHoneycombMR2.java
new file mode 100644
index 0000000..61a5924
--- /dev/null
+++ b/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorHoneycombMR2.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.os;
+
+import android.os.Parcel;
+
+class ParcelableCompatCreatorHoneycombMR2<T> extends ParcelableCompatCreatorBase<T> {
+
+    public ParcelableCompatCreatorHoneycombMR2(ParcelableCompatCreatorCallbacks<T> callbacks) {
+        super(callbacks);
+    }
+
+    public T createFromParcel(Parcel in, ClassLoader loader) {
+        return mCallbacks.createFromParcel(in, loader);
+    }
+}
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java b/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java
deleted file mode 100644
index 08acb55..0000000
--- a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.os;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-class ParcelableCompatCreatorHoneycombMR2Stub {
-    static <T> Parcelable.Creator<T> instantiate(ParcelableCompatCreatorCallbacks<T> callbacks) {
-        return new ParcelableCompatCreatorHoneycombMR2<T>(callbacks);
-    }
-}
-
-class ParcelableCompatCreatorHoneycombMR2<T> implements Parcelable.ClassLoaderCreator<T> {
-    private final ParcelableCompatCreatorCallbacks<T> mCallbacks;
-
-    public ParcelableCompatCreatorHoneycombMR2(ParcelableCompatCreatorCallbacks<T> callbacks) {
-        mCallbacks = callbacks;
-    }
-
-    public T createFromParcel(Parcel in) {
-        return mCallbacks.createFromParcel(in, null);
-    }
-
-    public T createFromParcel(Parcel in, ClassLoader loader) {
-        return mCallbacks.createFromParcel(in, loader);
-    }
-
-    public T[] newArray(int size) {
-        return mCallbacks.newArray(size);
-    }
-}
diff --git a/compat/java/android/support/v4/app/ActivityCompat.java b/compat/java/android/support/v4/app/ActivityCompat.java
index 478a153..b97d101 100644
--- a/compat/java/android/support/v4/app/ActivityCompat.java
+++ b/compat/java/android/support/v4/app/ActivityCompat.java
@@ -72,11 +72,12 @@
     }
 
     /**
-     * @deprecated Do not use this constructor. It will be removed and replaced
-     *             with a protected constructor in a future release.
+     * This class should not be instantiated, but the constructor must be
+     * visible for the class to be extended (ex. in support-v13).
      */
-    @Deprecated
-    public ActivityCompat() {}
+    protected ActivityCompat() {
+        // Not publicly instantiable, but may be extended.
+    }
 
     /**
      * Invalidate the activity's options menu, if able.
@@ -236,24 +237,32 @@
      */
     public static void finishAfterTransition(Activity activity) {
         if (Build.VERSION.SDK_INT >= 21) {
-            ActivityCompat21.finishAfterTransition(activity);
+            ActivityCompatApi21.finishAfterTransition(activity);
         } else {
             activity.finish();
         }
     }
 
     /**
-     * Backwards compatible implementation of {@link android.app.Activity#getReferrer()
-     * Activity.getReferrer}.  Uses the platform's implementation if available, otherwise
-     * only falls back to digging any explicitly specified referrer from the activity's intent.
+     * Return information about who launched this activity.  If the launching Intent
+     * contains an {@link Intent#EXTRA_REFERRER Intent.EXTRA_REFERRER},
+     * that will be returned as-is; otherwise, if known, an
+     * {@link Intent#URI_ANDROID_APP_SCHEME android-app:} referrer URI containing the
+     * package name that started the Intent will be returned.  This may return null if no
+     * referrer can be identified -- it is neither explicitly specified, nor is it known which
+     * application package was involved.
      *
-     * @deprecated Do not call this method. It will be removed and replaced
-     *             with a static method in a future release.
+     * <p>If called while inside the handling of {@link Activity#onNewIntent}, this function will
+     * return the referrer that submitted that new intent to the activity.  Otherwise, it
+     * always returns the referrer of the original Intent.</p>
+     *
+     * <p>Note that this is <em>not</em> a security feature -- you can not trust the
+     * referrer information, applications can spoof it.</p>
      */
-    @Deprecated
-    public Uri getReferrer(Activity activity) {
+    @Nullable
+    public static Uri getReferrer(Activity activity) {
         if (Build.VERSION.SDK_INT >= 22) {
-            return ActivityCompat22.getReferrer(activity);
+            return ActivityCompatApi22.getReferrer(activity);
         }
         Intent intent = activity.getIntent();
         Uri referrer = intent.getParcelableExtra("android.intent.extra.REFERRER");
@@ -280,7 +289,7 @@
         if (Build.VERSION.SDK_INT >= 23) {
             ActivityCompatApi23.setEnterSharedElementCallback(activity, createCallback23(callback));
         } else if (Build.VERSION.SDK_INT >= 21) {
-            ActivityCompat21.setEnterSharedElementCallback(activity, createCallback(callback));
+            ActivityCompatApi21.setEnterSharedElementCallback(activity, createCallback(callback));
         }
     }
 
@@ -298,19 +307,19 @@
         if (Build.VERSION.SDK_INT >= 23) {
             ActivityCompatApi23.setExitSharedElementCallback(activity, createCallback23(callback));
         } else if (Build.VERSION.SDK_INT >= 21) {
-            ActivityCompat21.setExitSharedElementCallback(activity, createCallback(callback));
+            ActivityCompatApi21.setExitSharedElementCallback(activity, createCallback(callback));
         }
     }
 
     public static void postponeEnterTransition(Activity activity) {
         if (Build.VERSION.SDK_INT >= 21) {
-            ActivityCompat21.postponeEnterTransition(activity);
+            ActivityCompatApi21.postponeEnterTransition(activity);
         }
     }
 
     public static void startPostponedEnterTransition(Activity activity) {
         if (Build.VERSION.SDK_INT >= 21) {
-            ActivityCompat21.startPostponedEnterTransition(activity);
+            ActivityCompatApi21.startPostponedEnterTransition(activity);
         }
     }
 
@@ -424,9 +433,9 @@
         return false;
     }
 
-    private static ActivityCompat21.SharedElementCallback21 createCallback(
+    private static ActivityCompatApi21.SharedElementCallback21 createCallback(
             SharedElementCallback callback) {
-        ActivityCompat21.SharedElementCallback21 newCallback = null;
+        ActivityCompatApi21.SharedElementCallback21 newCallback = null;
         if (callback != null) {
             newCallback = new ActivityCompat.SharedElementCallback21Impl(callback);
         }
@@ -443,7 +452,7 @@
     }
 
     private static class SharedElementCallback21Impl
-            extends ActivityCompat21.SharedElementCallback21 {
+            extends ActivityCompatApi21.SharedElementCallback21 {
 
         private SharedElementCallback mCallback;
 
diff --git a/compat/java/android/support/v4/app/NotificationCompat.java b/compat/java/android/support/v4/app/NotificationCompat.java
index 62c1a7b..cb02f41 100644
--- a/compat/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/java/android/support/v4/app/NotificationCompat.java
@@ -512,7 +512,11 @@
      */
     protected static class BuilderExtender {
         public Notification build(Builder b, NotificationBuilderWithBuilderAccessor builder) {
-            return builder.build();
+            Notification n = builder.build();
+            if (b.mContentView != null) {
+                n.contentView = b.mContentView;
+            }
+            return n;
         }
     }
 
@@ -521,7 +525,7 @@
         public Notification build(Builder b, BuilderExtender extender) {
             Notification result = b.mNotification;
             result = NotificationCompatBase.add(result, b.mContext,
-                    b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent);
+                    b.resolveTitle(), b.resolveText(), b.mContentIntent, b.mFullScreenIntent);
             // translate high priority requests into legacy flag
             if (b.mPriority > PRIORITY_DEFAULT) {
                 result.flags |= FLAG_HIGH_PRIORITY;
@@ -600,7 +604,7 @@
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             Notification notification = NotificationCompatHoneycomb.add(b.mContext, b.mNotification,
-                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView,
+                    b.resolveTitle(), b.resolveText(), b.mContentInfo, b.mTickerView,
                     b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon);
             if (b.mContentView != null) {
                 notification.contentView = b.mContentView;
@@ -613,15 +617,11 @@
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatIceCreamSandwich.Builder builder =
-                    new NotificationCompatIceCreamSandwich.Builder(
-                            b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
-                            b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
+                    new NotificationCompatIceCreamSandwich.Builder(b.mContext, b.mNotification,
+                            b.resolveTitle(), b.resolveText(), b.mContentInfo, b.mTickerView,
+                            b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
                             b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
-            Notification notification = extender.build(b, builder);
-            if (b.mContentView != null) {
-                notification.contentView = b.mContentView;
-            }
-            return notification;
+            return extender.build(b, builder);
         }
     }
 
@@ -629,7 +629,7 @@
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder(
-                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+                    b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras,
@@ -638,7 +638,10 @@
             addStyleToBuilderJellybean(builder, b.mStyle);
             Notification notification = extender.build(b, builder);
             if (b.mStyle != null) {
-                b.mStyle.addCompatExtras(getExtras(notification));
+                Bundle extras = getExtras(notification);
+                if (extras != null) {
+                    b.mStyle.addCompatExtras(extras);
+                }
             }
             return notification;
         }
@@ -697,7 +700,7 @@
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder(
-                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+                    b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly,
@@ -749,7 +752,7 @@
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder(
-                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+                    b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras,
@@ -807,7 +810,7 @@
         @Override
         public Notification build(Builder b, BuilderExtender extender) {
             NotificationCompatApi21.Builder builder = new NotificationCompatApi21.Builder(
-                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+                    b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
@@ -897,8 +900,6 @@
                         bigPictureStyle.mPicture,
                         bigPictureStyle.mBigLargeIcon,
                         bigPictureStyle.mBigLargeIconSet);
-            } else if (style instanceof MessagingStyle) {
-                // TODO implement BigText fallback
             }
         }
     }
@@ -1740,6 +1741,73 @@
             }
             return cs;
         }
+
+        /**
+         * @hide
+         */
+        public RemoteViews getContentView() {
+            return mContentView;
+        }
+
+        /**
+         * @hide
+         */
+        public RemoteViews getBigContentView() {
+            return mBigContentView;
+        }
+
+        /**
+         * @hide
+         */
+        public RemoteViews getHeadsUpContentView() {
+            return mHeadsUpContentView;
+        }
+
+        /**
+         * return when if it is showing or 0 otherwise
+         *
+         * @hide
+         */
+        public long getWhenIfShowing() {
+            return mShowWhen ? mNotification.when : 0;
+        }
+
+        /**
+         * @return the priority set on the notification
+         *
+         * @hide
+         */
+        public int getPriority() {
+            return mPriority;
+        }
+
+        /**
+         * @return the color of the notification
+         *
+         * @hide
+         */
+        public int getColor() {
+            return mColor;
+        }
+
+
+        /**
+         * @return the text of the notification
+         *
+         * @hide
+         */
+        protected CharSequence resolveText() {
+            return mContentText;
+        }
+
+        /**
+         * @return the title of the notification
+         *
+         * @hide
+         */
+        protected CharSequence resolveTitle() {
+            return mContentTitle;
+        }
     }
 
     /**
@@ -1919,8 +1987,9 @@
      * messages of varying types between any number of people.
      *
      * <br>
-     * If the platform does not provide large-format notifications, this method has no effect. The
-     * user will always see the normal notification view.
+     * In order to get a backwards compatible behavior, the app needs to use the v7 version of the
+     * notification builder together with this style, otherwise the user will see the normal
+     * notification view.
      * <br>
      * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like
      * so:
diff --git a/compat/java/android/support/v4/content/ContextCompat.java b/compat/java/android/support/v4/content/ContextCompat.java
index 6ffcd54..05486c2 100644
--- a/compat/java/android/support/v4/content/ContextCompat.java
+++ b/compat/java/android/support/v4/content/ContextCompat.java
@@ -51,11 +51,12 @@
     private static TypedValue sTempValue;
 
     /**
-     * @deprecated Do not use this constructor. It will be removed and replaced
-     *             with a protected constructor in a future release.
+     * This class should not be instantiated, but the constructor must be
+     * visible for the class to be extended (ex. in ActivityCompat).
      */
-    @Deprecated
-    public ContextCompat() {}
+    protected ContextCompat() {
+        // Not publicly instantiable, but may be extended.
+    }
 
     /**
      * Start a set of activities as a synthesized task stack, if able.
@@ -528,17 +529,6 @@
     }
 
     /**
-     * @removed
-     * @deprecated This method will be removed in a future release. Use
-     *             {@link #createDeviceProtectedStorageContext(Context)}
-     *             instead.
-     */
-    @Deprecated
-    public static Context createDeviceEncryptedStorageContext(Context context) {
-        return createDeviceProtectedStorageContext(context);
-    }
-
-    /**
      * Indicates if the storage APIs of this Context are backed by
      * device-encrypted storage.
      *
@@ -551,14 +541,4 @@
             return false;
         }
     }
-
-    /**
-     * @removed
-     * @deprecated This method will be removed in a future release. Use
-     *             {@link #isDeviceProtectedStorage(Context)} instead.
-     */
-    @Deprecated
-    public static boolean isDeviceEncryptedStorage(Context context) {
-        return isDeviceProtectedStorage(context);
-    }
 }
diff --git a/compat/java/android/support/v4/content/IntentCompat.java b/compat/java/android/support/v4/content/IntentCompat.java
index eaf7b1f..179824e 100644
--- a/compat/java/android/support/v4/content/IntentCompat.java
+++ b/compat/java/android/support/v4/content/IntentCompat.java
@@ -247,8 +247,6 @@
      * selector.
      * @return Returns a newly created Intent that can be used to launch the
      * activity as a main application entry.
-     *
-     * @see #setSelector(Intent)
      */
     public static Intent makeMainSelectorActivity(String selectorAction,
             String selectorCategory) {
diff --git a/compat/java/android/support/v4/net/ConnectivityManagerCompat.java b/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
index 9137d4a..90479c1 100644
--- a/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
+++ b/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
@@ -20,6 +20,10 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.os.Build;
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
@@ -37,8 +41,44 @@
 
     interface ConnectivityManagerCompatImpl {
         boolean isActiveNetworkMetered(ConnectivityManager cm);
+
+        @RestrictBackgroundStatus
+        int getRestrictBackgroundStatus(ConnectivityManager cm);
     }
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, value = {
+            RESTRICT_BACKGROUND_STATUS_DISABLED,
+            RESTRICT_BACKGROUND_STATUS_WHITELISTED,
+            RESTRICT_BACKGROUND_STATUS_ENABLED,
+    })
+    public @interface RestrictBackgroundStatus {
+    }
+
+    /**
+     * Device is not restricting metered network activity while application is running on
+     * background.
+     */
+    public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1;
+
+    /**
+     * Device is restricting metered network activity while application is running on background,
+     * but application is allowed to bypass it.
+     * <p>
+     * In this state, application should take action to mitigate metered network access.
+     * For example, a music streaming application should switch to a low-bandwidth bitrate.
+     */
+    public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2;
+
+    /**
+     * Device is restricting metered network activity while application is running on background.
+     * <p>
+     * In this state, application should not try to use the network while running on background,
+     * because it would be denied.
+     */
+    public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3;
+
     static class BaseConnectivityManagerCompatImpl implements ConnectivityManagerCompatImpl {
         @Override
         public boolean isActiveNetworkMetered(ConnectivityManager cm) {
@@ -64,27 +104,44 @@
                     return true;
             }
         }
+
+        @Override
+        public int getRestrictBackgroundStatus(ConnectivityManager cm) {
+            return RESTRICT_BACKGROUND_STATUS_ENABLED;
+        }
     }
 
     static class HoneycombMR2ConnectivityManagerCompatImpl
-            implements ConnectivityManagerCompatImpl {
+            extends BaseConnectivityManagerCompatImpl {
         @Override
         public boolean isActiveNetworkMetered(ConnectivityManager cm) {
             return ConnectivityManagerCompatHoneycombMR2.isActiveNetworkMetered(cm);
         }
     }
 
-    static class JellyBeanConnectivityManagerCompatImpl implements ConnectivityManagerCompatImpl {
+    static class JellyBeanConnectivityManagerCompatImpl
+            extends HoneycombMR2ConnectivityManagerCompatImpl {
         @Override
         public boolean isActiveNetworkMetered(ConnectivityManager cm) {
             return ConnectivityManagerCompatJellyBean.isActiveNetworkMetered(cm);
         }
     }
 
+    static class Api24ConnectivityManagerCompatImpl
+            extends JellyBeanConnectivityManagerCompatImpl {
+        @Override
+        public int getRestrictBackgroundStatus(ConnectivityManager cm) {
+            //noinspection ResourceType
+            return ConnectivityManagerCompatApi24.getRestrictBackgroundStatus(cm);
+        }
+    }
+
     private static final ConnectivityManagerCompatImpl IMPL;
 
     static {
-        if (Build.VERSION.SDK_INT >= 16) {
+        if (Build.VERSION.SDK_INT >= 24) {
+            IMPL = new Api24ConnectivityManagerCompatImpl();
+        } else if (Build.VERSION.SDK_INT >= 16) {
             IMPL = new JellyBeanConnectivityManagerCompatImpl();
         } else if (Build.VERSION.SDK_INT >= 13) {
             IMPL = new HoneycombMR2ConnectivityManagerCompatImpl();
@@ -96,9 +153,15 @@
     /**
      * Returns if the currently active data network is metered. A network is
      * classified as metered when the user is sensitive to heavy data usage on
-     * that connection. You should check this before doing large data transfers,
-     * and warn the user or delay the operation until another network is
-     * available.
+     * that connection due to monetary costs, data limitations or
+     * battery/performance issues. You should check this before doing large
+     * data transfers, and warn the user or delay the operation until another
+     * network is available.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @return {@code true} if large transfers should be avoided, otherwise
+     *        {@code false}.
      */
     public static boolean isActiveNetworkMetered(ConnectivityManager cm) {
         return IMPL.isActiveNetworkMetered(cm);
@@ -120,5 +183,18 @@
         }
     }
 
+    /**
+     * Determines if the calling application is subject to metered network restrictions while
+     * running on background.
+     *
+     * @return {@link #RESTRICT_BACKGROUND_STATUS_DISABLED},
+     *         {@link #RESTRICT_BACKGROUND_STATUS_ENABLED},
+     *         or {@link #RESTRICT_BACKGROUND_STATUS_WHITELISTED}
+     */
+    @RestrictBackgroundStatus
+    public static int getRestrictBackgroundStatus(ConnectivityManager cm) {
+        return IMPL.getRestrictBackgroundStatus(cm);
+    }
+
     private ConnectivityManagerCompat() {}
 }
diff --git a/compat/java/android/support/v4/os/ParcelableCompat.java b/compat/java/android/support/v4/os/ParcelableCompat.java
index 10c03b5..6c8820c 100644
--- a/compat/java/android/support/v4/os/ParcelableCompat.java
+++ b/compat/java/android/support/v4/os/ParcelableCompat.java
@@ -16,7 +16,6 @@
 
 package android.support.v4.os;
 
-import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
@@ -24,7 +23,6 @@
  * introduced after API level 4 in a backwards compatible fashion.
  */
 public final class ParcelableCompat {
-
     /**
      * Factory method for {@link Parcelable.Creator}.
      *
@@ -34,27 +32,9 @@
     public static <T> Parcelable.Creator<T> newCreator(
             ParcelableCompatCreatorCallbacks<T> callbacks) {
         if (android.os.Build.VERSION.SDK_INT >= 13) {
-            return ParcelableCompatCreatorHoneycombMR2Stub.instantiate(callbacks);
+            return new ParcelableCompatCreatorHoneycombMR2<T>(callbacks);
         }
-        return new CompatCreator<T>(callbacks);
-    }
-
-    static class CompatCreator<T> implements Parcelable.Creator<T> {
-        final ParcelableCompatCreatorCallbacks<T> mCallbacks;
-
-        public CompatCreator(ParcelableCompatCreatorCallbacks<T> callbacks) {
-            mCallbacks = callbacks;
-        }
-
-        @Override
-        public T createFromParcel(Parcel source) {
-            return mCallbacks.createFromParcel(source, null);
-        }
-
-        @Override
-        public T[] newArray(int size) {
-            return mCallbacks.newArray(size);
-        }
+        return new ParcelableCompatCreatorBase<T>(callbacks);
     }
 
     private ParcelableCompat() {}
diff --git a/compat/java/android/support/v4/util/Pair.java b/compat/java/android/support/v4/util/Pair.java
index 7f9e61e..46ea5cd 100644
--- a/compat/java/android/support/v4/util/Pair.java
+++ b/compat/java/android/support/v4/util/Pair.java
@@ -67,6 +67,11 @@
         return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
     }
 
+    @Override
+    public String toString() {
+        return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
+    }
+
     /**
      * Convenience method for creating an appropriately typed pair.
      * @param a the first object in the Pair
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index 4e14ec0..d9d3cfb 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -21,6 +21,7 @@
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.annotation.FloatRange;
 import android.support.annotation.IdRes;
@@ -31,6 +32,7 @@
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
 import android.util.Log;
+import android.view.Display;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -455,6 +457,7 @@
         void setSaveFromParentEnabled(View view, boolean enabled);
         void setActivated(View view, boolean activated);
         boolean isPaddingRelative(View view);
+        void setBackground(View view, Drawable background);
         ColorStateList getBackgroundTintList(View view);
         void setBackgroundTintList(View view, ColorStateList tintList);
         PorterDuff.Mode getBackgroundTintMode(View view);
@@ -484,6 +487,7 @@
         void offsetTopAndBottom(View view, int offset);
         void offsetLeftAndRight(View view, int offset);
         void setPointerIcon(View view, PointerIconCompat pointerIcon);
+        Display getDisplay(View view);
     }
 
     static class BaseViewCompatImpl implements ViewCompatImpl {
@@ -974,6 +978,11 @@
         }
 
         @Override
+        public void setBackground(View view, Drawable background) {
+            view.setBackgroundDrawable(background);
+        }
+
+        @Override
         public ColorStateList getBackgroundTintList(View view) {
             return ViewCompatBase.getBackgroundTintList(view);
         }
@@ -1147,6 +1156,11 @@
         public void setPointerIcon(View view, PointerIconCompat pointerIcon) {
             // no-op
         }
+
+        @Override
+        public Display getDisplay(View view) {
+            return ViewCompatBase.getDisplay(view);
+        }
     }
 
     static class HCViewCompatImpl extends BaseViewCompatImpl {
@@ -1486,6 +1500,11 @@
         public boolean hasOverlappingRendering(View view) {
             return ViewCompatJB.hasOverlappingRendering(view);
         }
+
+        @Override
+        public void setBackground(View view, Drawable background) {
+            ViewCompatJB.setBackground(view, background);
+        }
     }
 
     static class JbMr1ViewCompatImpl extends JBViewCompatImpl {
@@ -1539,6 +1558,11 @@
         public boolean isPaddingRelative(View view) {
             return ViewCompatJellybeanMr1.isPaddingRelative(view);
         }
+
+        @Override
+        public Display getDisplay(View view) {
+            return ViewCompatJellybeanMr1.getDisplay(view);
+        }
     }
 
     static class JbMr2ViewCompatImpl extends JbMr1ViewCompatImpl {
@@ -3082,6 +3106,16 @@
     }
 
     /**
+     * Set the background of the {@code view} to a given Drawable, or remove the background. If the
+     * background has padding, {@code view}'s padding is set to the background's padding. However,
+     * when a background is removed, this View's padding isn't touched. If setting the padding is
+     * desired, please use{@code setPadding(int, int, int, int)}.
+     */
+    public static void setBackground(View view, Drawable background) {
+        IMPL.setBackground(view, background);
+    }
+
+    /**
      * Return the tint applied to the background drawable, if specified.
      * <p>
      * Only returns meaningful info when running on API v21 or newer, or if {@code view}
@@ -3342,7 +3376,7 @@
      * <p>
      * Compatibility:
      * <ul>
-     *     <li>API < 18: Always returns {@code false}</li>
+     *     <li>API &lt; 18: Always returns {@code false}</li>
      * </ul>
      *
      * @return whether the view hierarchy is currently undergoing a layout pass
@@ -3364,7 +3398,7 @@
      * <p>
      * Compatibility:
      * <ul>
-     *     <li>API < 19: Always returns {@code false}</li>
+     *     <li>API &lt; 19: Always returns {@code false}</li>
      * </ul>
      *
      * @return true if layout direction has been resolved.
@@ -3391,7 +3425,7 @@
      * <p>
      * Compatibility:
      * <ul>
-     *     <li>API < 21: No-op
+     *     <li>API &lt; 21: No-op
      * </ul>
      *
      * @param z The visual z position of this view, in pixels.
@@ -3532,5 +3566,19 @@
         IMPL.setPointerIcon(view, pointerIcon);
     }
 
+    /**
+     * Gets the logical display to which the view's window has been attached.
+     * <p>
+     * Compatibility:
+     * <ul>
+     * <li>API &lt; 17: Returns the default display when the view is attached. Otherwise, null.
+     * </ul>
+     *
+     * @return The logical display, or null if the view is not currently attached to a window.
+     */
+    public static Display getDisplay(@NonNull View view) {
+        return IMPL.getDisplay(view);
+    }
+
     protected ViewCompat() {}
 }
diff --git a/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
index 4865a8b..c39ef2a 100644
--- a/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
@@ -17,6 +17,7 @@
 package android.support.v4.view;
 
 import android.graphics.Paint;
+import android.view.Display;
 import android.view.View;
 
 /**
@@ -63,4 +64,8 @@
     public static boolean isPaddingRelative(View view) {
         return view.isPaddingRelative();
     }
+
+    public static Display getDisplay(View view) {
+        return view.getDisplay();
+    }
 }
diff --git a/compat/jellybean/android/support/v4/view/ViewCompatJB.java b/compat/jellybean/android/support/v4/view/ViewCompatJB.java
index f1c7315..3d64da1 100644
--- a/compat/jellybean/android/support/v4/view/ViewCompatJB.java
+++ b/compat/jellybean/android/support/v4/view/ViewCompatJB.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.view;
 
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.view.View;
 import android.view.ViewParent;
@@ -89,4 +90,8 @@
     public static boolean hasOverlappingRendering(View view) {
         return view.hasOverlappingRendering();
     }
+
+    public static void setBackground(View view, Drawable drawable) {
+        view.setBackground(drawable);
+    }
 }
diff --git a/compat/tests/AndroidManifest.xml b/compat/tests/AndroidManifest.xml
index a46860a..8228476 100644
--- a/compat/tests/AndroidManifest.xml
+++ b/compat/tests/AndroidManifest.xml
@@ -37,6 +37,8 @@
         <activity
             android:name="android.support.v4.ThemedYellowActivity"
             android:theme="@style/YellowTheme" />
+
+        <activity android:name="android.support.v4.view.ViewCompatActivity"/>
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
similarity index 98%
rename from tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
rename to compat/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
index ea67375..8c1abcc 100644
--- a/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
+++ b/compat/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
@@ -20,15 +20,16 @@
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Bundle;
-import android.support.tests.R;
+import android.support.compat.test.R;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 
-import java.util.Arrays;
 import java.util.List;
 
 /**
  * Tests for {@link android.support.v4.app.NotificationCompat.Action.WearableExtender}.
  */
+@MediumTest
 public class NotificationCompatActionWearableExtenderTest extends AndroidTestCase {
 
     private int mIcon;
diff --git a/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
similarity index 98%
rename from tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
rename to compat/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
index 2a988ed..4e945dd 100644
--- a/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
+++ b/compat/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
@@ -20,8 +20,9 @@
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Bundle;
-import android.support.tests.R;
+import android.support.compat.test.R;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.Gravity;
 
 import java.util.Arrays;
@@ -30,6 +31,7 @@
 /**
  * Tests for {@link android.support.v4.app.NotificationCompat.WearableExtender}.
  */
+@MediumTest
 public class NotificationCompatWearableExtenderTest extends AndroidTestCase {
     public static final int CUSTOM_CONTENT_HEIGHT_DP = 256;
 
diff --git a/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java b/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
index 2905df0..fc144c5 100644
--- a/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
+++ b/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
@@ -16,8 +16,11 @@
 
 package android.support.v4.content;
 
+import static org.junit.Assert.fail;
+
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,8 +28,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import static org.junit.Assert.*;
-
 @RunWith(AndroidJUnit4.class)
 public class ModernAsyncTaskTest {
 
@@ -37,6 +38,7 @@
      *
      * @throws Throwable
      */
+    @LargeTest
     @Test
     public void testCancellationWithException() throws Throwable {
         final CountDownLatch readyToCancel = new CountDownLatch(1);
diff --git a/tests/java/android/support/v4/text/IcuCompatTest.java b/compat/tests/java/android/support/v4/text/IcuCompatTest.java
similarity index 72%
rename from tests/java/android/support/v4/text/IcuCompatTest.java
rename to compat/tests/java/android/support/v4/text/IcuCompatTest.java
index 6f7f459..20aaa9b 100644
--- a/tests/java/android/support/v4/text/IcuCompatTest.java
+++ b/compat/tests/java/android/support/v4/text/IcuCompatTest.java
@@ -16,13 +16,22 @@
 
 package android.support.v4.text;
 
+import android.os.Build;
+import android.test.suitebuilder.annotation.SmallTest;
+
 import junit.framework.TestCase;
 
 import java.util.Locale;
 
+@SmallTest
 public class IcuCompatTest extends TestCase {
     public void testMaximizeAndGetScript() {
         assertEquals("Latn", ICUCompat.maximizeAndGetScript(new Locale("en", "US")));
-        assertEquals("Visp", ICUCompat.maximizeAndGetScript(Locale.forLanguageTag("en-Visp-US")));
+
+        // Script tags were added to java.util.Locale only on API 21.
+        if (Build.VERSION.SDK_INT >= 21) {
+            assertEquals(
+                    "Visp", ICUCompat.maximizeAndGetScript(Locale.forLanguageTag("en-Visp-US")));
+        }
     }
 }
diff --git a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
index f867188..45779c7 100644
--- a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
+++ b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -214,16 +215,9 @@
         if (Locale.US.equals(Locale.getDefault())) {
             assertTrue(LinkifyCompat.addLinks(spannable, Linkify.PHONE_NUMBERS));
             URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-            assertEquals(9, spans.length);
-            assertEquals("tel:8121234562", spans[0].getURL());
-            assertEquals("tel:8121234563", spans[1].getURL());
-            assertEquals("tel:8005551210", spans[2].getURL());
-            assertEquals("tel:8005551211", spans[3].getURL());
-            assertEquals("tel:5551212", spans[4].getURL());
-            assertEquals("tel:+4408121234564", spans[5].getURL());
-            assertEquals("tel:+4408121234565", spans[6].getURL());
-            assertEquals("tel:+18005551213", spans[7].getURL());
-            assertEquals("tel:+18005551214", spans[8].getURL());
+            // We cannot assert the contents of the spans as support library falls back to the
+            // framework libphonenumber which behaves differently for different API levels.
+            assertNotEquals("There should be more than zero phone number spans.", 0, spans.length);
         }
 
         try {
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/compat/tests/java/android/support/v4/view/ViewCompatActivity.java
similarity index 62%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to compat/tests/java/android/support/v4/view/ViewCompatActivity.java
index 3946f1d..28ff642 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/compat/tests/java/android/support/v4/view/ViewCompatActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-package android.support.v4.app;
+package android.support.v4.view;
 
-import android.app.Activity;
-import android.net.Uri;
+import android.support.compat.test.R;
+import android.support.v4.BaseTestActivity;
 
-class ActivityCompat22 {
-    public static Uri getReferrer(Activity activity) {
-        return activity.getReferrer();
+public class ViewCompatActivity extends BaseTestActivity {
+
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.view_compat_activity;
     }
+
 }
diff --git a/compat/tests/java/android/support/v4/view/ViewCompatTest.java b/compat/tests/java/android/support/v4/view/ViewCompatTest.java
index c4217a5..0b102a6 100644
--- a/compat/tests/java/android/support/v4/view/ViewCompatTest.java
+++ b/compat/tests/java/android/support/v4/view/ViewCompatTest.java
@@ -15,18 +15,39 @@
  */
 package android.support.v4.view;
 
+import android.app.Activity;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.Display;
 import android.view.View;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.compat.test.R;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
 
 @RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ViewCompatTest {
+@MediumTest
+public class ViewCompatTest extends BaseInstrumentationTestCase<ViewCompatActivity> {
+
+    private View mView;
+
+    public ViewCompatTest() {
+        super(ViewCompatActivity.class);
+    }
+
+    @Before
+    public void setUp() {
+        final Activity activity = mActivityTestRule.getActivity();
+        mView = activity.findViewById(R.id.view);
+    }
+
     @Test
     public void testConstants() {
         // Compat constants must match core constants since they can be used interchangeably
@@ -34,4 +55,18 @@
         assertEquals("LTR constants", View.LAYOUT_DIRECTION_LTR, ViewCompat.LAYOUT_DIRECTION_LTR);
         assertEquals("RTL constants", View.LAYOUT_DIRECTION_RTL, ViewCompat.LAYOUT_DIRECTION_RTL);
     }
+
+    @Test
+    public void testGetDisplay() {
+        final Display display = ViewCompat.getDisplay(mView);
+        assertNotNull(display);
+    }
+
+    @Test
+    public void testGetDisplay_returnsNullForUnattachedView() {
+        final View view = new View(mActivityTestRule.getActivity());
+        final Display display = ViewCompat.getDisplay(view);
+        assertNull(display);
+    }
+
 }
diff --git a/tests/res/drawable/action_icon.xml b/compat/tests/res/drawable/action_icon.xml
similarity index 100%
rename from tests/res/drawable/action_icon.xml
rename to compat/tests/res/drawable/action_icon.xml
diff --git a/tests/res/drawable/action_icon2.xml b/compat/tests/res/drawable/action_icon2.xml
similarity index 100%
rename from tests/res/drawable/action_icon2.xml
rename to compat/tests/res/drawable/action_icon2.xml
diff --git a/tests/res/drawable/content_icon.xml b/compat/tests/res/drawable/content_icon.xml
similarity index 100%
rename from tests/res/drawable/content_icon.xml
rename to compat/tests/res/drawable/content_icon.xml
diff --git a/tests/res/drawable/content_icon2.xml b/compat/tests/res/drawable/content_icon2.xml
similarity index 100%
rename from tests/res/drawable/content_icon2.xml
rename to compat/tests/res/drawable/content_icon2.xml
diff --git a/compat/tests/res/layout/view_compat_activity.xml b/compat/tests/res/layout/view_compat_activity.xml
new file mode 100644
index 0000000..2a8acac
--- /dev/null
+++ b/compat/tests/res/layout/view_compat_activity.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    android:id="@+id/container"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <View
+        android:id="@+id/view"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:background="#f00"/>
+
+</FrameLayout>
diff --git a/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java b/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
index 452b033..197f96e 100644
--- a/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
+++ b/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
@@ -110,6 +110,9 @@
     }
 
     private static class ActionBarDrawerToggleImplBase implements ActionBarDrawerToggleImpl {
+        ActionBarDrawerToggleImplBase() {
+        }
+
         @Override
         public Drawable getThemeUpIndicator(Activity activity) {
             return null;
@@ -130,6 +133,9 @@
     }
 
     private static class ActionBarDrawerToggleImplHC implements ActionBarDrawerToggleImpl {
+        ActionBarDrawerToggleImplHC() {
+        }
+
         @Override
         public Drawable getThemeUpIndicator(Activity activity) {
             return ActionBarDrawerToggleHoneycomb.getThemeUpIndicator(activity);
@@ -151,6 +157,9 @@
 
     private static class ActionBarDrawerToggleImplJellybeanMR2
             implements ActionBarDrawerToggleImpl {
+        ActionBarDrawerToggleImplJellybeanMR2() {
+        }
+
         @Override
         public Drawable getThemeUpIndicator(Activity activity) {
             return ActionBarDrawerToggleJellybeanMR2.getThemeUpIndicator(activity);
@@ -189,7 +198,7 @@
     // android.R.id.home as defined by public API in v11
     private static final int ID_HOME = 0x0102002c;
 
-    private final Activity mActivity;
+    final Activity mActivity;
     private final Delegate mActivityImpl;
     private final DrawerLayout mDrawerLayout;
     private boolean mDrawerIndicatorEnabled = true;
@@ -505,7 +514,7 @@
         private float mPosition;
         private float mOffset;
 
-        private SlideDrawable(Drawable wrapped) {
+        SlideDrawable(Drawable wrapped) {
             super(wrapped, 0);
         }
 
diff --git a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
index 21aaae5..e638d05 100644
--- a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
+++ b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
@@ -67,9 +67,9 @@
 public final class AsyncLayoutInflater {
     private static final String TAG = "AsyncLayoutInflater";
 
-    private LayoutInflater mInflater;
-    private Handler mHandler;
-    private InflateThread mInflateThread;
+    LayoutInflater mInflater;
+    Handler mHandler;
+    InflateThread mInflateThread;
 
     public AsyncLayoutInflater(@NonNull Context context) {
         mInflater = new BasicInflater(context);
@@ -116,6 +116,9 @@
         int resid;
         View view;
         OnInflateFinishedListener callback;
+
+        InflateRequest() {
+        }
     }
 
     private static class BasicInflater extends LayoutInflater {
diff --git a/core-ui/java/android/support/v4/view/PagerTabStrip.java b/core-ui/java/android/support/v4/view/PagerTabStrip.java
index c53595b..f4c0b21 100644
--- a/core-ui/java/android/support/v4/view/PagerTabStrip.java
+++ b/core-ui/java/android/support/v4/view/PagerTabStrip.java
@@ -24,6 +24,7 @@
 import android.support.annotation.ColorInt;
 import android.support.annotation.ColorRes;
 import android.support.annotation.DrawableRes;
+import android.support.v4.content.ContextCompat;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -140,7 +141,7 @@
      * @param resId Resource ID of a color resource to load
      */
     public void setTabIndicatorColorResource(@ColorRes int resId) {
-        setTabIndicatorColor(getContext().getResources().getColor(resId));
+        setTabIndicatorColor(ContextCompat.getColor(getContext(), resId));
     }
 
     /**
diff --git a/core-ui/java/android/support/v4/view/PagerTitleStrip.java b/core-ui/java/android/support/v4/view/PagerTitleStrip.java
index 477e271..d569cd4 100644
--- a/core-ui/java/android/support/v4/view/PagerTitleStrip.java
+++ b/core-ui/java/android/support/v4/view/PagerTitleStrip.java
@@ -22,6 +22,7 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.annotation.FloatRange;
+import android.support.v4.widget.TextViewCompat;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -54,7 +55,7 @@
     TextView mNextText;
 
     private int mLastKnownCurrentPage = -1;
-    private float mLastKnownPositionOffset = -1;
+    float mLastKnownPositionOffset = -1;
     private int mScaledTextSpacing;
     private int mGravity;
 
@@ -127,9 +128,9 @@
         final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
         final int textAppearance = a.getResourceId(0, 0);
         if (textAppearance != 0) {
-            mPrevText.setTextAppearance(context, textAppearance);
-            mCurrText.setTextAppearance(context, textAppearance);
-            mNextText.setTextAppearance(context, textAppearance);
+            TextViewCompat.setTextAppearance(mPrevText, textAppearance);
+            TextViewCompat.setTextAppearance(mCurrText, textAppearance);
+            TextViewCompat.setTextAppearance(mNextText, textAppearance);
         }
         final int textSize = a.getDimensionPixelSize(1, 0);
         if (textSize != 0) {
@@ -480,6 +481,9 @@
             ViewPager.OnAdapterChangeListener {
         private int mScrollState;
 
+        PageListener() {
+        }
+
         @Override
         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
             if (positionOffset > 0.5f) {
diff --git a/core-ui/java/android/support/v4/view/ViewPager.java b/core-ui/java/android/support/v4/view/ViewPager.java
index ba4a6a6..50b16fc 100644
--- a/core-ui/java/android/support/v4/view/ViewPager.java
+++ b/core-ui/java/android/support/v4/view/ViewPager.java
@@ -32,6 +32,7 @@
 import android.support.annotation.DrawableRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.os.ParcelableCompat;
 import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -121,7 +122,7 @@
 
     private static final int MIN_FLING_VELOCITY = 400; // dips
 
-    private static final int[] LAYOUT_ATTRS = new int[] {
+    static final int[] LAYOUT_ATTRS = new int[] {
         android.R.attr.layout_gravity
     };
 
@@ -159,8 +160,8 @@
 
     private final Rect mTempRect = new Rect();
 
-    private PagerAdapter mAdapter;
-    private int mCurItem;   // Index of currently displayed page.
+    PagerAdapter mAdapter;
+    int mCurItem;   // Index of currently displayed page.
     private int mRestoredCurItem = -1;
     private Parcelable mRestoredAdapterState = null;
     private ClassLoader mRestoredClassLoader = null;
@@ -243,6 +244,7 @@
     private OnPageChangeListener mInternalPageChangeListener;
     private List<OnAdapterChangeListener> mAdapterChangeListeners;
     private PageTransformer mPageTransformer;
+    private int mPageTransformerLayerType;
     private Method mSetChildrenDrawingOrderEnabled;
 
     private static final int DRAW_ORDER_DEFAULT = 0;
@@ -486,7 +488,7 @@
         super.onDetachedFromWindow();
     }
 
-    private void setScrollState(int newState) {
+    void setScrollState(int newState) {
         if (mScrollState == newState) {
             return;
         }
@@ -749,18 +751,47 @@
     }
 
     /**
-     * Set a {@link PageTransformer} that will be called for each attached page whenever
+     * Sets a {@link PageTransformer} that will be called for each attached page whenever
      * the scroll position is changed. This allows the application to apply custom property
-     * transformations to each page, overriding the default sliding look and feel.
+     * transformations to each page, overriding the default sliding behavior.
      *
      * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist.
-     * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p>
+     * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.
+     * By default, calling this method will cause contained pages to use
+     * {@link ViewCompat#LAYER_TYPE_HARDWARE}. This layer type allows custom alpha transformations,
+     * but it will cause issues if any of your pages contain a {@link android.view.SurfaceView}
+     * and you have not called {@link android.view.SurfaceView#setZOrderOnTop(boolean)} to put that
+     * {@link android.view.SurfaceView} above your app content. To disable this behavior, call
+     * {@link #setPageTransformer(boolean,PageTransformer,int)} and pass
+     * {@link ViewCompat#LAYER_TYPE_NONE} for {@code pageLayerType}.</p>
      *
      * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
      *                            to be drawn from last to first instead of first to last.
      * @param transformer PageTransformer that will modify each page's animation properties
      */
     public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
+        setPageTransformer(reverseDrawingOrder, transformer, ViewCompat.LAYER_TYPE_HARDWARE);
+    }
+
+    /**
+     * Sets a {@link PageTransformer} that will be called for each attached page whenever
+     * the scroll position is changed. This allows the application to apply custom property
+     * transformations to each page, overriding the default sliding behavior.
+     *
+     * <p><em>Note:</em> Prior to Android 3.0 ({@link Build.VERSION_CODES#HONEYCOMB API 11}),
+     * the property animation APIs did not exist. As a result, setting a PageTransformer prior
+     * to API 11 will have no effect.</p>
+     *
+     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
+     *                            to be drawn from last to first instead of first to last.
+     * @param transformer PageTransformer that will modify each page's animation properties
+     * @param pageLayerType View layer type that should be used for ViewPager pages. It should be
+     *                      either {@link ViewCompat#LAYER_TYPE_HARDWARE},
+     *                      {@link ViewCompat#LAYER_TYPE_SOFTWARE}, or
+     *                      {@link ViewCompat#LAYER_TYPE_NONE}.
+     */
+    public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer,
+            int pageLayerType) {
         if (Build.VERSION.SDK_INT >= 11) {
             final boolean hasTransformer = transformer != null;
             final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
@@ -768,6 +799,7 @@
             setChildrenDrawingOrderEnabledCompat(hasTransformer);
             if (hasTransformer) {
                 mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
+                mPageTransformerLayerType = pageLayerType;
             } else {
                 mDrawingOrder = DRAW_ORDER_DEFAULT;
             }
@@ -898,7 +930,7 @@
      * @param resId Resource ID of a drawable to display between pages
      */
     public void setPageMarginDrawable(@DrawableRes int resId) {
-        setPageMarginDrawable(getContext().getResources().getDrawable(resId));
+        setPageMarginDrawable(ContextCompat.getDrawable(getContext(), resId));
     }
 
     @Override
@@ -2007,7 +2039,7 @@
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             final int layerType = enable
-                    ? ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE;
+                    ? mPageTransformerLayerType : ViewCompat.LAYER_TYPE_NONE;
             ViewCompat.setLayerType(getChildAt(i), layerType, null);
         }
     }
@@ -3077,6 +3109,9 @@
     }
 
     private class PagerObserver extends DataSetObserver {
+        PagerObserver() {
+        }
+
         @Override
         public void onChanged() {
             dataSetChanged();
diff --git a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java b/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
index bf4f1e4..4291a25 100644
--- a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
+++ b/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
@@ -134,13 +134,13 @@
     private static final int VERTICAL = 1;
 
     /** Scroller used to control acceleration toward maximum velocity. */
-    private final ClampedScroller mScroller = new ClampedScroller();
+    final ClampedScroller mScroller = new ClampedScroller();
 
     /** Interpolator used to scale velocity with touch position. */
     private final Interpolator mEdgeInterpolator = new AccelerateInterpolator();
 
     /** The view to auto-scroll. Might not be the source of touch events. */
-    private final View mTarget;
+    final View mTarget;
 
     /** Runnable used to animate scrolling. */
     private Runnable mRunnable;
@@ -170,13 +170,13 @@
     private boolean mAlreadyDelayed;
 
     /** Whether to reset the scroller start time on the next animation. */
-    private boolean mNeedsReset;
+    boolean mNeedsReset;
 
     /** Whether to send a cancel motion event to the target view. */
-    private boolean mNeedsCancel;
+    boolean mNeedsCancel;
 
     /** Whether the auto-scroller is actively scrolling. */
-    private boolean mAnimating;
+    boolean mAnimating;
 
     /** Whether the auto-scroller is enabled. */
     private boolean mEnabled;
@@ -488,7 +488,7 @@
     /**
      * @return whether the target is able to scroll in the requested direction
      */
-    private boolean shouldAnimate() {
+    boolean shouldAnimate() {
         final ClampedScroller scroller = mScroller;
         final int verticalDirection = scroller.getVerticalDirection();
         final int horizontalDirection = scroller.getHorizontalDirection();
@@ -649,7 +649,7 @@
         return 0;
     }
 
-    private static int constrain(int value, int min, int max) {
+    static int constrain(int value, int min, int max) {
         if (value > max) {
             return max;
         } else if (value < min) {
@@ -659,7 +659,7 @@
         }
     }
 
-    private static float constrain(float value, float min, float max) {
+    static float constrain(float value, float min, float max) {
         if (value > max) {
             return max;
         } else if (value < min) {
@@ -673,7 +673,7 @@
      * Sends a {@link MotionEvent#ACTION_CANCEL} event to the target view,
      * canceling any ongoing touch events.
      */
-    private void cancelTargetTouch() {
+    void cancelTargetTouch() {
         final long eventTime = SystemClock.uptimeMillis();
         final MotionEvent cancel = MotionEvent.obtain(
                 eventTime, eventTime, MotionEvent.ACTION_CANCEL, 0, 0, 0);
@@ -682,6 +682,9 @@
     }
 
     private class ScrollAnimationRunnable implements Runnable {
+        ScrollAnimationRunnable() {
+        }
+
         @Override
         public void run() {
             if (!mAnimating) {
diff --git a/core-ui/java/android/support/v4/widget/CircleImageView.java b/core-ui/java/android/support/v4/widget/CircleImageView.java
index b04b56e..371c9a2 100644
--- a/core-ui/java/android/support/v4/widget/CircleImageView.java
+++ b/core-ui/java/android/support/v4/widget/CircleImageView.java
@@ -24,6 +24,7 @@
 import android.graphics.Shader;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.OvalShape;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.view.ViewCompat;
 import android.view.animation.Animation;
 import android.widget.ImageView;
@@ -46,7 +47,7 @@
     private static final int SHADOW_ELEVATION = 4;
 
     private Animation.AnimationListener mListener;
-    private int mShadowRadius;
+    int mShadowRadius;
 
     CircleImageView(Context context, int color) {
         super(context);
@@ -71,7 +72,7 @@
             setPadding(padding, padding, padding, padding);
         }
         circle.getPaint().setColor(color);
-        setBackgroundDrawable(circle);
+        ViewCompat.setBackground(this, circle);
     }
 
     private boolean elevationSupported() {
@@ -113,7 +114,7 @@
      * @param colorRes Id of a color resource.
      */
     public void setBackgroundColorRes(int colorRes) {
-        setBackgroundColor(getContext().getResources().getColor(colorRes));
+        setBackgroundColor(ContextCompat.getColor(getContext(), colorRes));
     }
 
     @Override
diff --git a/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java b/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
index 3335b9f..98b63a4 100644
--- a/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
+++ b/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
@@ -31,13 +31,13 @@
     private static final int MIN_SHOW_TIME = 500; // ms
     private static final int MIN_DELAY = 500; // ms
 
-    private long mStartTime = -1;
+    long mStartTime = -1;
 
-    private boolean mPostedHide = false;
+    boolean mPostedHide = false;
 
-    private boolean mPostedShow = false;
+    boolean mPostedShow = false;
 
-    private boolean mDismissed = false;
+    boolean mDismissed = false;
 
     private final Runnable mDelayedHide = new Runnable() {
 
diff --git a/core-ui/java/android/support/v4/widget/CursorAdapter.java b/core-ui/java/android/support/v4/widget/CursorAdapter.java
index d95f048..8beb4ab 100644
--- a/core-ui/java/android/support/v4/widget/CursorAdapter.java
+++ b/core-ui/java/android/support/v4/widget/CursorAdapter.java
@@ -476,6 +476,9 @@
     }
 
     private class MyDataSetObserver extends DataSetObserver {
+        MyDataSetObserver() {
+        }
+
         @Override
         public void onChanged() {
             mDataValid = true;
diff --git a/core-ui/java/android/support/v4/widget/DrawerLayout.java b/core-ui/java/android/support/v4/widget/DrawerLayout.java
index 938cb0b..36b465b 100644
--- a/core-ui/java/android/support/v4/widget/DrawerLayout.java
+++ b/core-ui/java/android/support/v4/widget/DrawerLayout.java
@@ -173,12 +173,12 @@
 
     private static final float TOUCH_SLOP_SENSITIVITY = 1.f;
 
-    private static final int[] LAYOUT_ATTRS = new int[] {
+    static final int[] LAYOUT_ATTRS = new int[] {
             android.R.attr.layout_gravity
     };
 
     /** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */
-    private static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
+    static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
 
     /** Whether the drawer shadow comes from setting elevation on the drawer. */
     private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION =
@@ -506,7 +506,7 @@
      * @param gravity Which drawer the shadow should apply to
      */
     public void setDrawerShadow(@DrawableRes int resId, @EdgeGravity int gravity) {
-        setDrawerShadow(getResources().getDrawable(resId), gravity);
+        setDrawerShadow(ContextCompat.getDrawable(getContext(), resId), gravity);
     }
 
     /**
@@ -1864,7 +1864,7 @@
         return findVisibleDrawer() != null;
     }
 
-    private View findVisibleDrawer() {
+    View findVisibleDrawer() {
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             final View child = getChildAt(i);
@@ -1995,7 +1995,7 @@
         }
     }
 
-    private static boolean includeChildForAccessibility(View child) {
+    static boolean includeChildForAccessibility(View child) {
         // If the child is not important for accessibility we make
         // sure this hides the entire subtree rooted at it as the
         // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDATS is not
@@ -2146,7 +2146,7 @@
             postDelayed(mPeekRunnable, PEEK_DELAY);
         }
 
-        private void peekDrawer() {
+        void peekDrawer() {
             final View toCapture;
             final int childLeft;
             final int peekDistance = mDragger.getEdgeSize();
@@ -2226,9 +2226,9 @@
         private static final int FLAG_IS_CLOSING = 0x4;
 
         public int gravity = Gravity.NO_GRAVITY;
-        private float onScreen;
-        private boolean isPeeking;
-        private int openState;
+        float onScreen;
+        boolean isPeeking;
+        int openState;
 
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
diff --git a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
index 3e44962..bb43456 100644
--- a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -717,7 +717,7 @@
      *         about the specified item
      */
     @NonNull
-    private AccessibilityNodeInfoCompat obtainAccessibilityNodeInfo(int virtualViewId) {
+    AccessibilityNodeInfoCompat obtainAccessibilityNodeInfo(int virtualViewId) {
         if (virtualViewId == HOST_ID) {
             return createNodeForHost();
         }
@@ -867,7 +867,7 @@
         return node;
     }
 
-    private boolean performAction(int virtualViewId, int action, Bundle arguments) {
+    boolean performAction(int virtualViewId, int action, Bundle arguments) {
         switch (virtualViewId) {
             case HOST_ID:
                 return performActionForHost(action, arguments);
@@ -1221,6 +1221,9 @@
      * Exposes a virtual view hierarchy to the accessibility framework.
      */
     private class MyNodeProvider extends AccessibilityNodeProviderCompat {
+        MyNodeProvider() {
+        }
+
         @Override
         public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) {
             // The caller takes ownership of the node and is expected to
@@ -1234,5 +1237,15 @@
         public boolean performAction(int virtualViewId, int action, Bundle arguments) {
             return ExploreByTouchHelper.this.performAction(virtualViewId, action, arguments);
         }
+
+        @Override
+        public AccessibilityNodeInfoCompat findFocus(int focusType) {
+            int focusedId = (focusType == AccessibilityNodeInfoCompat.FOCUS_ACCESSIBILITY) ?
+                    mAccessibilityFocusedVirtualViewId : mKeyboardFocusedVirtualViewId;
+            if (focusedId == INVALID_ID) {
+                return null;
+            }
+            return createAccessibilityNodeInfo(focusedId);
+        }
     }
 }
diff --git a/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java b/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
index 6affe47..4cf43fa 100644
--- a/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
+++ b/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
@@ -50,7 +50,7 @@
  */
 class MaterialProgressDrawable extends Drawable implements Animatable {
     private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
+    static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
 
     private static final float FULL_ROTATION = 1080.0f;
     @Retention(RetentionPolicy.SOURCE)
@@ -110,7 +110,7 @@
     private Resources mResources;
     private View mParent;
     private Animation mAnimation;
-    private float mRotationCount;
+    float mRotationCount;
     private double mWidth;
     private double mHeight;
     boolean mFinishing;
@@ -299,7 +299,7 @@
         mRing.resetOriginals();
     }
 
-    private float getMinProgressArc(Ring ring) {
+    float getMinProgressArc(Ring ring) {
         return (float) Math.toRadians(
                 ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
     }
@@ -329,7 +329,7 @@
      * The new ring color will be a translation from the starting ring color to
      * the next color.
      */
-    private void updateRingColor(float interpolatedTime, Ring ring) {
+    void updateRingColor(float interpolatedTime, Ring ring) {
         if (interpolatedTime > COLOR_START_DELAY_OFFSET) {
             // scale the interpolatedTime so that the full
             // transformation from 0 - 1 takes place in the
@@ -340,7 +340,7 @@
         }
     }
 
-    private void applyFinishTranslation(float interpolatedTime, Ring ring) {
+    void applyFinishTranslation(float interpolatedTime, Ring ring) {
         // shrink back down and complete a full rotation before
         // starting other circles
         // Rotation goes between [0..1].
diff --git a/core-ui/java/android/support/v4/widget/NestedScrollView.java b/core-ui/java/android/support/v4/widget/NestedScrollView.java
index 3e4c55f..0d40bc9 100644
--- a/core-ui/java/android/support/v4/widget/NestedScrollView.java
+++ b/core-ui/java/android/support/v4/widget/NestedScrollView.java
@@ -998,7 +998,7 @@
         return clampedX || clampedY;
     }
 
-    private int getScrollRange() {
+    int getScrollRange() {
         int scrollRange = 0;
         if (getChildCount() > 0) {
             View child = getChildAt(0);
diff --git a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java b/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
index 7467989..1e5479b 100644
--- a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
+++ b/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
@@ -31,6 +31,7 @@
 import android.os.Parcelable;
 import android.support.annotation.ColorInt;
 import android.support.annotation.DrawableRes;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.os.ParcelableCompat;
 import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
@@ -146,13 +147,13 @@
     /**
      * The child view that can slide, if any.
      */
-    private View mSlideableView;
+    View mSlideableView;
 
     /**
      * How far the panel is offset from its closed position.
      * range [0, 1] where 0 = closed, 1 = open.
      */
-    private float mSlideOffset;
+    float mSlideOffset;
 
     /**
      * How far the non-sliding panel is parallaxed from its usual position when open.
@@ -163,13 +164,13 @@
     /**
      * How far in pixels the slideable panel may move.
      */
-    private int mSlideRange;
+    int mSlideRange;
 
     /**
      * A panel view is locked into internal scrolling or another condition that
      * is preventing a drag.
      */
-    private boolean mIsUnableToDrag;
+    boolean mIsUnableToDrag;
 
     /**
      * Distance in pixels to parallax the fixed pane by when fully closed
@@ -181,19 +182,19 @@
 
     private PanelSlideListener mPanelSlideListener;
 
-    private final ViewDragHelper mDragHelper;
+    final ViewDragHelper mDragHelper;
 
     /**
      * Stores whether or not the pane was open the last time it was slideable.
      * If open/close operations are invoked this state is modified. Used by
      * instance state save/restore.
      */
-    private boolean mPreservedOpenState;
+    boolean mPreservedOpenState;
     private boolean mFirstLayout = true;
 
     private final Rect mTmpRect = new Rect();
 
-    private final ArrayList<DisableLayerRunnable> mPostedRunnables =
+    final ArrayList<DisableLayerRunnable> mPostedRunnables =
             new ArrayList<DisableLayerRunnable>();
 
     static final SlidingPanelLayoutImpl IMPL;
@@ -945,7 +946,7 @@
         return mCanSlide;
     }
 
-    private void onPanelDragged(int newLeft) {
+    void onPanelDragged(int newLeft) {
         if (mSlideableView == null) {
             // This can happen if we're aborting motion during layout because everything now fits.
             mSlideOffset = 0;
@@ -1043,7 +1044,7 @@
         return result;
     }
 
-    private void invalidateChildRegion(View v) {
+    void invalidateChildRegion(View v) {
         IMPL.invalidateChildRegion(this, v);
     }
 
@@ -1145,7 +1146,7 @@
      * @param resId Resource ID of a drawable to use
      */
     public void setShadowResourceLeft(int resId) {
-        setShadowDrawableLeft(getResources().getDrawable(resId));
+        setShadowDrawableLeft(ContextCompat.getDrawable(getContext(), resId));
     }
 
     /**
@@ -1155,10 +1156,9 @@
      * @param resId Resource ID of a drawable to use
      */
     public void setShadowResourceRight(int resId) {
-        setShadowDrawableRight(getResources().getDrawable(resId));
+        setShadowDrawableRight(ContextCompat.getDrawable(getContext(), resId));
     }
 
-
     @Override
     public void draw(Canvas c) {
         super.draw(c);
@@ -1312,6 +1312,9 @@
 
     private class DragHelperCallback extends ViewDragHelper.Callback {
 
+        DragHelperCallback() {
+        }
+
         @Override
         public boolean tryCaptureView(View child, int pointerId) {
             if (mIsUnableToDrag) {
@@ -1467,7 +1470,7 @@
             super(superState);
         }
 
-        private SavedState(Parcel in, ClassLoader loader) {
+        SavedState(Parcel in, ClassLoader loader) {
             super(in, loader);
             isOpen = in.readInt() != 0;
         }
@@ -1658,7 +1661,7 @@
         }
     }
 
-    private boolean isLayoutRtlSupport() {
+    boolean isLayoutRtlSupport() {
         return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
     }
 }
diff --git a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
index 769a08b..4ebdeed 100644
--- a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -23,6 +23,7 @@
 import android.support.annotation.ColorRes;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.NestedScrollingChild;
 import android.support.v4.view.NestedScrollingChildHelper;
@@ -102,8 +103,8 @@
     private static final int DEFAULT_CIRCLE_TARGET = 64;
 
     private View mTarget; // the target of the gesture
-    private OnRefreshListener mListener;
-    private boolean mRefreshing = false;
+    OnRefreshListener mListener;
+    boolean mRefreshing = false;
     private int mTouchSlop;
     private float mTotalDragDistance = -1;
 
@@ -118,14 +119,14 @@
     private boolean mNestedScrollInProgress;
 
     private int mMediumAnimationDuration;
-    private int mCurrentTargetOffsetTop;
+    int mCurrentTargetOffsetTop;
 
     private float mInitialMotionY;
     private float mInitialDownY;
     private boolean mIsBeingDragged;
     private int mActivePointerId = INVALID_POINTER;
     // Whether this item is scaled up rather than clipped
-    private boolean mScale;
+    boolean mScale;
 
     // Target is returning to its start offset because it was cancelled or a
     // refresh was triggered.
@@ -135,16 +136,18 @@
         android.R.attr.enabled
     };
 
-    private CircleImageView mCircleView;
+    CircleImageView mCircleView;
     private int mCircleViewIndex = -1;
 
     protected int mFrom;
 
-    private float mStartingScale;
+    float mStartingScale;
 
     protected int mOriginalOffsetTop;
 
-    private MaterialProgressDrawable mProgress;
+    int mSpinnerOffsetEnd;
+
+    MaterialProgressDrawable mProgress;
 
     private Animation mScaleAnimation;
 
@@ -156,14 +159,12 @@
 
     private Animation mScaleDownToStartAnimation;
 
-    private float mSpinnerFinalOffset;
-
-    private boolean mNotify;
+    boolean mNotify;
 
     private int mCircleDiameter;
 
     // Whether the client has set a custom starting position;
-    private boolean mUsingCustomStart;
+    boolean mUsingCustomStart;
 
     private OnChildScrollUpCallback mChildScrollUpCallback;
 
@@ -194,7 +195,7 @@
         }
     };
 
-    private void reset() {
+    void reset() {
         mCircleView.clearAnimation();
         mProgress.stop();
         mCircleView.setVisibility(View.GONE);
@@ -250,13 +251,29 @@
     public void setProgressViewOffset(boolean scale, int start, int end) {
         mScale = scale;
         mOriginalOffsetTop = start;
-        mSpinnerFinalOffset = end;
+        mSpinnerOffsetEnd = end;
         mUsingCustomStart = true;
         reset();
         mRefreshing = false;
     }
 
     /**
+     * @return The offset in pixels from the top of this view at which the progress spinner should
+     *         appear.
+     */
+    public int getProgressViewStartOffset() {
+        return mOriginalOffsetTop;
+    }
+
+    /**
+     * @return The offset in pixels from the top of this view at which the progress spinner should
+     *         come to rest after a successful swipe gesture.
+     */
+    public int getProgressViewEndOffset() {
+        return mSpinnerOffsetEnd;
+    }
+
+    /**
      * The refresh indicator resting position is always positioned near the top
      * of the refreshing content. This position is a consistent location, but
      * can be adjusted in either direction based on whether or not there is a
@@ -270,7 +287,7 @@
      *            gesture.
      */
     public void setProgressViewEndTarget(boolean scale, int end) {
-        mSpinnerFinalOffset = end;
+        mSpinnerOffsetEnd = end;
         mScale = scale;
         mCircleView.invalidate();
     }
@@ -328,8 +345,8 @@
         createProgressView();
         ViewCompat.setChildrenDrawingOrderEnabled(this, true);
         // the absolute offset has to take into account that the circle starts at an offset
-        mSpinnerFinalOffset = DEFAULT_CIRCLE_TARGET * metrics.density;
-        mTotalDragDistance = mSpinnerFinalOffset;
+        mSpinnerOffsetEnd = (int) (DEFAULT_CIRCLE_TARGET * metrics.density);
+        mTotalDragDistance = mSpinnerOffsetEnd;
         mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
 
         mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
@@ -395,9 +412,9 @@
             mRefreshing = refreshing;
             int endTarget = 0;
             if (!mUsingCustomStart) {
-                endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop);
+                endTarget = mSpinnerOffsetEnd + mOriginalOffsetTop;
             } else {
-                endTarget = (int) mSpinnerFinalOffset;
+                endTarget = mSpinnerOffsetEnd;
             }
             setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop,
                     true /* requires update */);
@@ -434,7 +451,7 @@
      * Pre API 11, this does an alpha animation.
      * @param progress
      */
-    private void setAnimationProgress(float progress) {
+    void setAnimationProgress(float progress) {
         if (isAlphaUsedForScale()) {
             setColorViewAlpha((int) (progress * MAX_ALPHA));
         } else {
@@ -456,7 +473,7 @@
         }
     }
 
-    private void startScaleDownAnimation(Animation.AnimationListener listener) {
+    void startScaleDownAnimation(Animation.AnimationListener listener) {
         mScaleDownAnimation = new Animation() {
             @Override
             public void applyTransformation(float interpolatedTime, Transformation t) {
@@ -512,7 +529,7 @@
      * @param colorRes Resource id of the color.
      */
     public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) {
-        setProgressBackgroundColorSchemeColor(getResources().getColor(colorRes));
+        setProgressBackgroundColorSchemeColor(ContextCompat.getColor(getContext(), colorRes));
     }
 
     /**
@@ -541,10 +558,10 @@
      * @param colorResIds
      */
     public void setColorSchemeResources(@ColorRes int... colorResIds) {
-        final Resources res = getResources();
+        final Context context = getContext();
         int[] colorRes = new int[colorResIds.length];
         for (int i = 0; i < colorResIds.length; i++) {
-            colorRes[i] = res.getColor(colorResIds[i]);
+            colorRes[i] = ContextCompat.getColor(context, colorResIds[i]);
         }
         setColorSchemeColors(colorRes);
     }
@@ -915,8 +932,8 @@
         float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
         float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
         float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;
-        float slingshotDist = mUsingCustomStart ? mSpinnerFinalOffset - mOriginalOffsetTop
-                : mSpinnerFinalOffset;
+        float slingshotDist = mUsingCustomStart ? mSpinnerOffsetEnd - mOriginalOffsetTop
+                : mSpinnerOffsetEnd;
         float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2)
                 / slingshotDist);
         float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(
@@ -1113,9 +1130,9 @@
             int targetTop = 0;
             int endTarget = 0;
             if (!mUsingCustomStart) {
-                endTarget = (int) (mSpinnerFinalOffset - Math.abs(mOriginalOffsetTop));
+                endTarget = mSpinnerOffsetEnd - Math.abs(mOriginalOffsetTop);
             } else {
-                endTarget = (int) mSpinnerFinalOffset;
+                endTarget = mSpinnerOffsetEnd;
             }
             targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
             int offset = targetTop - mCircleView.getTop();
@@ -1124,7 +1141,7 @@
         }
     };
 
-    private void moveToStart(float interpolatedTime) {
+    void moveToStart(float interpolatedTime) {
         int targetTop = 0;
         targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
         int offset = targetTop - mCircleView.getTop();
@@ -1162,7 +1179,7 @@
         mCircleView.startAnimation(mScaleDownToStartAnimation);
     }
 
-    private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
+    void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
         mCircleView.bringToFront();
         ViewCompat.offsetTopAndBottom(mCircleView, offset);
         mCurrentTargetOffsetTop = mCircleView.getTop();
diff --git a/core-utils/tests/AndroidManifest.xml b/core-utils/tests/AndroidManifest.xml
index d80e735..8a30a93 100644
--- a/core-utils/tests/AndroidManifest.xml
+++ b/core-utils/tests/AndroidManifest.xml
@@ -35,7 +35,13 @@
         <uses-library android:name="android.test.runner" />
         <activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
         <activity android:name="android.support.v4.widget.TestActivity"/>
-
+        <activity android:name="android.support.v4.provider.GrantActivity"
+                  android:label="_GrantActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
         <provider
             android:name="android.support.v4.content.FileProvider"
             android:authorities="moocow"
diff --git a/tests/java/android/support/v4/provider/DocumentFileTest.java b/core-utils/tests/java/android/support/v4/provider/DocumentFileTest.java
similarity index 98%
rename from tests/java/android/support/v4/provider/DocumentFileTest.java
rename to core-utils/tests/java/android/support/v4/provider/DocumentFileTest.java
index 26c10a4..9dd5a51 100644
--- a/tests/java/android/support/v4/provider/DocumentFileTest.java
+++ b/core-utils/tests/java/android/support/v4/provider/DocumentFileTest.java
@@ -22,7 +22,8 @@
 import android.os.Environment;
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
-import android.util.Log;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -34,7 +35,11 @@
 
 /**
  * Tests for {@link DocumentFile}
+ *
  */
+// These tests fail so it is marked @Suppress. Fix is tracked in b/27168036
+@Suppress
+@MediumTest
 public class DocumentFileTest extends AndroidTestCase {
 
     private Uri treeUri;
diff --git a/tests/java/android/support/tests/GrantActivity.java b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
similarity index 97%
rename from tests/java/android/support/tests/GrantActivity.java
rename to core-utils/tests/java/android/support/v4/provider/GrantActivity.java
index 854357f..c4dbb27 100644
--- a/tests/java/android/support/tests/GrantActivity.java
+++ b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.tests;
+package android.support.v4.provider;
 
 import android.app.Activity;
 import android.content.ContentResolver;
diff --git a/design/Android.mk b/design/Android.mk
index e9ba5b6..38ca592 100644
--- a/design/Android.mk
+++ b/design/Android.mk
@@ -101,7 +101,8 @@
     android-support-design-res \
     android-support-v4 \
     android-support-v7-appcompat \
-    android-support-v7-recyclerview
+    android-support-v7-recyclerview \
+    android-support-transition
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
@@ -115,7 +116,8 @@
     android-support-design-res \
     android-support-v4 \
     android-support-v7-appcompat \
-    android-support-v7-recyclerview
+    android-support-v7-recyclerview \
+    android-support-transition
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/design/AndroidManifest.xml b/design/AndroidManifest.xml
index 82f19db..d51186d 100644
--- a/design/AndroidManifest.xml
+++ b/design/AndroidManifest.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
           package="android.support.design">
-    <uses-sdk android:minSdkVersion="9"/>
+    <uses-sdk android:minSdkVersion="9"
+              tools:overrideLibrary="android.support.transition"/>
     <application />
 </manifest>
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
similarity index 68%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
index 3946f1d..22501c1 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package android.support.v4.app;
+package android.support.design.internal;
 
-import android.app.Activity;
-import android.net.Uri;
+import android.view.ViewGroup;
 
-class ActivityCompat22 {
-    public static Uri getReferrer(Activity activity) {
-        return activity.getReferrer();
+class BottomNavigationAnimationHelperBase {
+    void beginDelayedTransition(ViewGroup view) {
+        // Do nothing.
     }
 }
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 9670035..872fae4 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -16,6 +16,7 @@
 
 package android.support.design.widget;
 
+import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
@@ -25,6 +26,7 @@
 import android.graphics.drawable.GradientDrawable;
 import android.support.annotation.Nullable;
 import android.support.design.R;
+import android.support.v4.content.ContextCompat;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
@@ -148,13 +150,13 @@
     }
 
     CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
-        final Resources resources = mView.getResources();
+        final Context context = mView.getContext();
         CircularBorderDrawable borderDrawable = newCircularDrawable();
         borderDrawable.setGradientColors(
-                resources.getColor(R.color.design_fab_stroke_top_outer_color),
-                resources.getColor(R.color.design_fab_stroke_top_inner_color),
-                resources.getColor(R.color.design_fab_stroke_end_inner_color),
-                resources.getColor(R.color.design_fab_stroke_end_outer_color));
+                ContextCompat.getColor(context, R.color.design_fab_stroke_top_outer_color),
+                ContextCompat.getColor(context, R.color.design_fab_stroke_top_inner_color),
+                ContextCompat.getColor(context, R.color.design_fab_stroke_end_inner_color),
+                ContextCompat.getColor(context, R.color.design_fab_stroke_end_outer_color));
         borderDrawable.setBorderWidth(borderWidth);
         borderDrawable.setBorderTint(backgroundTint);
         return borderDrawable;
diff --git a/design/base/android/support/design/widget/ShadowDrawableWrapper.java b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
index bd7997f..dfb8e1d 100644
--- a/design/base/android/support/design/widget/ShadowDrawableWrapper.java
+++ b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
@@ -16,7 +16,7 @@
 
 package android.support.design.widget;
 
-import android.content.res.Resources;
+import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.LinearGradient;
 import android.graphics.Paint;
@@ -28,6 +28,7 @@
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
 import android.support.design.R;
+import android.support.v4.content.ContextCompat;
 import android.support.v7.graphics.drawable.DrawableWrapper;
 
 /**
@@ -78,13 +79,13 @@
      */
     private boolean mPrintedShadowClipWarning = false;
 
-    public ShadowDrawableWrapper(Resources resources, Drawable content, float radius,
+    public ShadowDrawableWrapper(Context context, Drawable content, float radius,
             float shadowSize, float maxShadowSize) {
         super(content);
 
-        mShadowStartColor = resources.getColor(R.color.design_fab_shadow_start_color);
-        mShadowMiddleColor = resources.getColor(R.color.design_fab_shadow_mid_color);
-        mShadowEndColor = resources.getColor(R.color.design_fab_shadow_end_color);
+        mShadowStartColor = ContextCompat.getColor(context, R.color.design_fab_shadow_start_color);
+        mShadowMiddleColor = ContextCompat.getColor(context, R.color.design_fab_shadow_mid_color);
+        mShadowEndColor = ContextCompat.getColor(context, R.color.design_fab_shadow_end_color);
 
         mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
         mCornerShadowPaint.setStyle(Paint.Style.FILL);
diff --git a/design/base/android/support/design/widget/StateListAnimator.java b/design/base/android/support/design/widget/StateListAnimator.java
index 7ef944e..4378ef9 100644
--- a/design/base/android/support/design/widget/StateListAnimator.java
+++ b/design/base/android/support/design/widget/StateListAnimator.java
@@ -25,7 +25,7 @@
     private final ArrayList<Tuple> mTuples = new ArrayList<>();
 
     private Tuple mLastMatch = null;
-    private ValueAnimatorCompat mRunningAnimator = null;
+    ValueAnimatorCompat mRunningAnimator = null;
 
     private final ValueAnimatorCompat.AnimatorListener mAnimationListener
             = new ValueAnimatorCompat.AnimatorListenerAdapter() {
@@ -105,7 +105,7 @@
         final int[] mSpecs;
         final ValueAnimatorCompat mAnimator;
 
-        private Tuple(int[] specs, ValueAnimatorCompat animator) {
+        Tuple(int[] specs, ValueAnimatorCompat animator) {
             mSpecs = specs;
             mAnimator = animator;
         }
diff --git a/design/build.gradle b/design/build.gradle
index 4407ba9..8ae45d7 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -6,6 +6,7 @@
     compile project(':support-v4')
     compile project(':support-appcompat-v7')
     compile project(':support-recyclerview-v7')
+    compile project(':support-transition')
 
     androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
         exclude module: 'support-annotations'
diff --git a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
index 2cd3de5..d17691c 100644
--- a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
+++ b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
@@ -87,7 +87,7 @@
         mContentBackground = new LayerDrawable(layers);
 
         mShadowDrawable = new ShadowDrawableWrapper(
-                mView.getResources(),
+                mView.getContext(),
                 mContentBackground,
                 mShadowViewDelegate.getRadius(),
                 mElevation,
@@ -246,6 +246,9 @@
     }
 
     private class ResetElevationAnimation extends ShadowAnimatorImpl {
+        ResetElevationAnimation() {
+        }
+
         @Override
         protected float getTargetShadowSize() {
             return mElevation;
@@ -253,6 +256,9 @@
     }
 
     private class ElevateToTranslationZAnimation extends ShadowAnimatorImpl {
+        ElevateToTranslationZAnimation() {
+        }
+
         @Override
         protected float getTargetShadowSize() {
             return mElevation + mPressedTranslationZ;
@@ -260,6 +266,9 @@
     }
 
     private class DisabledElevationAnimation extends ShadowAnimatorImpl {
+        DisabledElevationAnimation() {
+        }
+
         @Override
         protected float getTargetShadowSize() {
             return 0f;
diff --git a/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java b/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java
new file mode 100644
index 0000000..6681d0b
--- /dev/null
+++ b/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.internal;
+
+import android.support.transition.AutoTransition;
+import android.support.transition.TransitionManager;
+import android.support.transition.TransitionSet;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.view.ViewGroup;
+
+class BottomNavigationAnimationHelperIcs extends BottomNavigationAnimationHelperBase {
+    private static final long ACTIVE_ANIMATION_DURATION_MS = 115L;
+
+    private final TransitionSet mSet;
+
+    BottomNavigationAnimationHelperIcs() {
+        mSet = new AutoTransition();
+        mSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
+        mSet.setDuration(ACTIVE_ANIMATION_DURATION_MS);
+        mSet.setInterpolator(new FastOutSlowInInterpolator());
+        TextScale textScale = new TextScale();
+        mSet.addTransition(textScale);
+    }
+
+    void beginDelayedTransition(ViewGroup view) {
+        TransitionManager.beginDelayedTransition(view, mSet);
+    }
+}
diff --git a/design/ics/android/support/design/internal/TextScale.java b/design/ics/android/support/design/internal/TextScale.java
new file mode 100644
index 0000000..219353e
--- /dev/null
+++ b/design/ics/android/support/design/internal/TextScale.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.internal;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.support.transition.Transition;
+import android.support.transition.TransitionValues;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public class TextScale extends Transition {
+    private static final String PROPNAME_SCALE = "android:textscale:scale";
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        captureValues(transitionValues);
+    }
+
+    private void captureValues(TransitionValues transitionValues) {
+        if (transitionValues.view instanceof TextView) {
+            TextView textview = (TextView) transitionValues.view;
+            transitionValues.values.put(PROPNAME_SCALE, textview.getScaleX());
+        }
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues == null || endValues == null || !(startValues.view instanceof TextView)
+                || !(endValues.view instanceof TextView)) {
+            return null;
+        }
+        final TextView view = (TextView) endValues.view;
+        Map<String, Object> startVals = startValues.values;
+        Map<String, Object> endVals = endValues.values;
+        final float startSize = startVals.get(PROPNAME_SCALE) != null ? (float) startVals.get(
+                PROPNAME_SCALE) : 1f;
+        final float endSize = endVals.get(PROPNAME_SCALE) != null ? (float) endVals.get(
+                PROPNAME_SCALE) : 1f;
+        if (startSize == endSize) {
+            return null;
+        }
+
+        ValueAnimator animator = ValueAnimator.ofFloat(startSize, endSize);
+
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                float animatedValue = (float) valueAnimator.getAnimatedValue();
+                view.setScaleX(animatedValue);
+                view.setScaleY(animatedValue);
+            }
+        });
+        return animator;
+    }
+}
diff --git a/design/res-public/values/public_styles.xml b/design/res-public/values/public_styles.xml
index a7c0af6..0dcde45 100644
--- a/design/res-public/values/public_styles.xml
+++ b/design/res-public/values/public_styles.xml
@@ -24,6 +24,7 @@
     <public type="style" name="TextAppearance.Design.Snackbar.Message"/>
     <public type="style" name="TextAppearance.Design.Tab"/>
     <public type="style" name="Theme.Design"/>
+    <public type="style" name="Theme.Design.BottomNavigationView"/>
     <public type="style" name="Theme.Design.BottomSheetDialog"/>
     <public type="style" name="Theme.Design.Light"/>
     <public type="style" name="Theme.Design.Light.BottomSheetDialog"/>
diff --git a/design/res/drawable-v21/design_bottom_navigation_item_background.xml b/design/res/drawable-v21/design_bottom_navigation_item_background.xml
new file mode 100644
index 0000000..f30f08b
--- /dev/null
+++ b/design/res/drawable-v21/design_bottom_navigation_item_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?attr/colorPrimary" />
\ No newline at end of file
diff --git a/design/res/drawable/design_bottom_navigation_item_background.xml b/design/res/drawable/design_bottom_navigation_item_background.xml
new file mode 100644
index 0000000..7674f42
--- /dev/null
+++ b/design/res/drawable/design_bottom_navigation_item_background.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <solid android:color="#ff0000"/>
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="#ffffff"/>
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/design/res/layout/design_bottom_navigation_item.xml b/design/res/layout/design_bottom_navigation_item.xml
new file mode 100644
index 0000000..cc7bb5f
--- /dev/null
+++ b/design/res/layout/design_bottom_navigation_item.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/design_bottom_navigation_margin"
+        android:layout_marginBottom="@dimen/design_bottom_navigation_margin"
+        android:duplicateParentState="true" />
+    <android.support.design.internal.BaselineLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/design_bottom_navigation_margin"
+        android:layout_gravity="bottom|center_horizontal"
+        android:duplicateParentState="true">
+        <TextView
+            android:id="@+id/smallLabel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="@dimen/design_bottom_navigation_text_size"
+            android:duplicateParentState="true" />
+        <TextView
+            android:id="@+id/largeLabel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:visibility="invisible"
+            android:textSize="@dimen/design_bottom_navigation_active_text_size"
+            android:duplicateParentState="true" />
+    </android.support.design.internal.BaselineLayout>
+</merge>
\ No newline at end of file
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 7ae7433..545a82e 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -463,4 +463,12 @@
         <attr name="textColorError" format="color" />
     </declare-styleable>
 
+    <declare-styleable name="BottomNavigationView">
+        <!-- The menu resource to inflate and populate items from. -->
+        <attr name="menu"/>
+        <attr name="itemIconTint"/>
+        <attr name="itemTextColor"/>
+        <attr name="itemBackground"/>
+    </declare-styleable>
+
 </resources>
diff --git a/design/res/values/dimens.xml b/design/res/values/dimens.xml
index 546d137..63e98b8 100644
--- a/design/res/values/dimens.xml
+++ b/design/res/values/dimens.xml
@@ -62,6 +62,7 @@
     <dimen name="design_bottom_navigation_text_size">12sp</dimen>
     <dimen name="design_bottom_navigation_active_text_size">14sp</dimen>
     <dimen name="design_bottom_navigation_margin">8dp</dimen>
+    <dimen name="design_bottom_navigation_item_min_width">56dp</dimen>
     <dimen name="design_bottom_navigation_item_max_width">96dp</dimen>
     <dimen name="design_bottom_navigation_active_item_max_width">168dp</dimen>
 
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
index 848d2cf..c8b9cd5 100644
--- a/design/res/values/styles.xml
+++ b/design/res/values/styles.xml
@@ -42,6 +42,10 @@
         <item name="tabMode">fixed</item>
     </style>
 
+    <style name="Widget.Design.BottomNavigationView" parent="">
+        <item name="itemBackground">?attr/selectableItemBackgroundBorderless</item>
+    </style>
+
     <style name="Base.Widget.Design.TabLayout" parent="android:Widget">
         <item name="tabMaxWidth">@dimen/design_tab_max_width</item>
         <item name="tabIndicatorColor">?attr/colorAccent</item>
diff --git a/design/src/android/support/design/internal/BaselineLayout.java b/design/src/android/support/design/internal/BaselineLayout.java
new file mode 100644
index 0000000..eac3542
--- /dev/null
+++ b/design/src/android/support/design/internal/BaselineLayout.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.ViewUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple ViewGroup that aligns all the views inside on a baseline.
+ *
+ * @hide
+ */
+public class BaselineLayout extends ViewGroup {
+    private int mBaseline = -1;
+
+    public BaselineLayout(Context context) {
+        super(context, null, 0);
+    }
+
+    public BaselineLayout(Context context, AttributeSet attrs) {
+        super(context, attrs, 0);
+    }
+
+    public BaselineLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int count = getChildCount();
+        int maxWidth = 0;
+        int maxHeight = 0;
+        int maxChildBaseline = -1;
+        int maxChildDescent = -1;
+        int childState = 0;
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            measureChild(child, widthMeasureSpec, heightMeasureSpec);
+            final int baseline = child.getBaseline();
+            if (baseline != -1) {
+                maxChildBaseline = Math.max(maxChildBaseline, baseline);
+                maxChildDescent = Math.max(maxChildDescent, child.getMeasuredHeight() - baseline);
+            }
+            maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
+            maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+            childState = ViewUtils.combineMeasuredStates(childState,
+                    ViewCompat.getMeasuredState(child));
+        }
+        if (maxChildBaseline != -1) {
+            maxHeight = Math.max(maxHeight, maxChildBaseline + maxChildDescent);
+            mBaseline = maxChildBaseline;
+        }
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+        setMeasuredDimension(
+                ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int count = getChildCount();
+        final int parentLeft = getPaddingLeft();
+        final int parentRight = right - left - getPaddingRight();
+        final int parentContentWidth = parentRight - parentLeft;
+        final int parentTop = getPaddingTop();
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            final int width = child.getMeasuredWidth();
+            final int height = child.getMeasuredHeight();
+
+            final int childLeft = parentLeft + (parentContentWidth - width) / 2;
+            final int childTop;
+            if (mBaseline != -1 && child.getBaseline() != -1) {
+                childTop = parentTop + mBaseline - child.getBaseline();
+            } else {
+                childTop = parentTop;
+            }
+
+            child.layout(childLeft, childTop, childLeft + width, childTop + height);
+        }
+    }
+
+    @Override
+    public int getBaseline() {
+        return mBaseline;
+    }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
new file mode 100644
index 0000000..d5e8176
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationItemView.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.design.R;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuView;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * @hide
+ */
+public class BottomNavigationItemView extends FrameLayout implements MenuView.ItemView {
+    public static final int INVALID_ITEM_POSITION = -1;
+
+    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
+
+    private final int mDefaultMargin;
+    private final int mShiftAmount;
+    private final float mScaleUpFactor;
+    private final float mScaleDownFactor;
+
+    private boolean mShiftingMode;
+
+    private ImageView mIcon;
+    private final TextView mSmallLabel;
+    private final TextView mLargeLabel;
+    private int mItemPosition = INVALID_ITEM_POSITION;
+
+    private MenuItemImpl mItemData;
+
+    private ColorStateList mIconTint;
+
+    public BottomNavigationItemView(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public BottomNavigationItemView(@NonNull Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BottomNavigationItemView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        final Resources res = getResources();
+        int inactiveLabelSize =
+                res.getDimensionPixelSize(R.dimen.design_bottom_navigation_text_size);
+        int activeLabelSize = res.getDimensionPixelSize(
+                R.dimen.design_bottom_navigation_active_text_size);
+        mDefaultMargin = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_margin);
+        mShiftAmount = inactiveLabelSize - activeLabelSize;
+        mScaleUpFactor = 1f * activeLabelSize / inactiveLabelSize;
+        mScaleDownFactor = 1f * inactiveLabelSize / activeLabelSize;
+
+        LayoutInflater.from(context).inflate(R.layout.design_bottom_navigation_item, this, true);
+        setBackgroundResource(R.drawable.design_bottom_navigation_item_background);
+        mIcon = (ImageView) findViewById(R.id.icon);
+        mSmallLabel = (TextView) findViewById(R.id.smallLabel);
+        mLargeLabel = (TextView) findViewById(R.id.largeLabel);
+
+    }
+
+    @Override
+    public void initialize(MenuItemImpl itemData, int menuType) {
+        mItemData = itemData;
+        setCheckable(itemData.isCheckable());
+        setChecked(itemData.isChecked());
+        setEnabled(itemData.isEnabled());
+        setIcon(itemData.getIcon());
+        setTitle(itemData.getTitle());
+        setId(itemData.getItemId());
+    }
+
+    public void setItemPosition(int position) {
+        mItemPosition = position;
+    }
+
+    public int getItemPosition() {
+        return mItemPosition;
+    }
+
+    public void setShiftingMode(boolean enabled) {
+        mShiftingMode = enabled;
+    }
+
+    @Override
+    public MenuItemImpl getItemData() {
+        return mItemData;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        mSmallLabel.setText(title);
+        mLargeLabel.setText(title);
+    }
+
+    @Override
+    public void setCheckable(boolean checkable) {
+        refreshDrawableState();
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        mItemData.setChecked(checked);
+
+        ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2);
+        ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline());
+        ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2);
+        ViewCompat.setPivotY(mSmallLabel, mSmallLabel.getBaseline());
+        if (mShiftingMode) {
+            if (checked) {
+                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+                iconParams.topMargin = mDefaultMargin;
+                mIcon.setLayoutParams(iconParams);
+                mLargeLabel.setVisibility(VISIBLE);
+                ViewCompat.setScaleX(mLargeLabel, 1f);
+                ViewCompat.setScaleY(mLargeLabel, 1f);
+            } else {
+                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+                iconParams.gravity = Gravity.CENTER;
+                iconParams.topMargin = mDefaultMargin;
+                mIcon.setLayoutParams(iconParams);
+                mLargeLabel.setVisibility(INVISIBLE);
+                ViewCompat.setScaleX(mLargeLabel, 0.5f);
+                ViewCompat.setScaleY(mLargeLabel, 0.5f);
+            }
+            mSmallLabel.setVisibility(INVISIBLE);
+        } else {
+            if (checked) {
+                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+                iconParams.topMargin = mDefaultMargin + mShiftAmount;
+                mIcon.setLayoutParams(iconParams);
+                mLargeLabel.setVisibility(VISIBLE);
+                mSmallLabel.setVisibility(INVISIBLE);
+
+                ViewCompat.setScaleX(mLargeLabel, 1f);
+                ViewCompat.setScaleY(mLargeLabel, 1f);
+                ViewCompat.setScaleX(mSmallLabel, mScaleUpFactor);
+                ViewCompat.setScaleY(mSmallLabel, mScaleUpFactor);
+            } else {
+                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+                iconParams.topMargin = mDefaultMargin;
+                mIcon.setLayoutParams(iconParams);
+                mLargeLabel.setVisibility(INVISIBLE);
+                mSmallLabel.setVisibility(VISIBLE);
+
+                ViewCompat.setScaleX(mLargeLabel, mScaleDownFactor);
+                ViewCompat.setScaleY(mLargeLabel, mScaleDownFactor);
+                ViewCompat.setScaleX(mSmallLabel, 1f);
+                ViewCompat.setScaleY(mSmallLabel, 1f);
+            }
+        }
+
+        refreshDrawableState();
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        mSmallLabel.setEnabled(enabled);
+        mLargeLabel.setEnabled(enabled);
+        mIcon.setEnabled(enabled);
+    }
+
+    @Override
+    public int[] onCreateDrawableState(final int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+        if (mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) {
+            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+        }
+        return drawableState;
+    }
+
+    @Override
+    public void setShortcut(boolean showShortcut, char shortcutKey) {
+    }
+
+    @Override
+    public void setIcon(Drawable icon) {
+        if (icon != null) {
+            Drawable.ConstantState state = icon.getConstantState();
+            icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate();
+            DrawableCompat.setTintList(icon, mIconTint);
+        }
+        mIcon.setImageDrawable(icon);
+    }
+
+    @Override
+    public boolean prefersCondensedTitle() {
+        return false;
+    }
+
+    @Override
+    public boolean showsIcon() {
+        return true;
+    }
+
+    public void setIconTintList(ColorStateList tint) {
+        mIconTint = tint;
+        if (mItemData != null) {
+            // Update the icon so that the tint takes effect
+            setIcon(mItemData.getIcon());
+        }
+    }
+
+    public void setTextColor(ColorStateList color) {
+        mSmallLabel.setTextColor(color);
+        mLargeLabel.setTextColor(color);
+    }
+
+    public void setItemBackground(int background) {
+        Drawable backgroundDrawable = background == 0
+                ? null : ContextCompat.getDrawable(getContext(), background);
+        ViewCompat.setBackground(this, backgroundDrawable);
+    }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationMenu.java b/design/src/android/support/design/internal/BottomNavigationMenu.java
new file mode 100644
index 0000000..d813ea2
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationMenu.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.support.v7.view.menu.MenuBuilder;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+/**
+ * @hide
+ */
+public final class BottomNavigationMenu extends MenuBuilder {
+    public static final int MAX_ITEM_COUNT = 5;
+
+    public BottomNavigationMenu(Context context) {
+        super(context);
+    }
+
+    @Override
+    public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
+        throw new UnsupportedOperationException("BottomNavigationView does not support submenus");
+    }
+
+    @Override
+    protected MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
+        if (size() + 1 > MAX_ITEM_COUNT) {
+            throw new IllegalArgumentException(
+                    "Maximum number of items supported by BottomNavigationView is " + MAX_ITEM_COUNT
+                            + ". Limit can be checked with BottomNavigationView#getMaxItemCount()");
+        }
+        return super.addInternal(group, id, categoryOrder, title);
+    }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java
new file mode 100644
index 0000000..ec1b542
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationMenuView.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.design.R;
+import android.support.v4.util.Pools;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuView;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * @hide
+ */
+public class BottomNavigationMenuView extends ViewGroup implements MenuView {
+
+    private final int mInactiveItemMaxWidth;
+    private final int mInactiveItemMinWidth;
+    private final int mActiveItemMaxWidth;
+    private final int mItemHeight;
+    private final OnClickListener mOnClickListener;
+    private final BottomNavigationAnimationHelperBase mAnimationHelper;
+    private static final Pools.Pool<BottomNavigationItemView> sItemPool =
+            new Pools.SynchronizedPool<>(5);
+
+    private boolean mShiftingMode = true;
+
+    private BottomNavigationItemView[] mButtons;
+    private int mActiveButton = 0;
+    private ColorStateList mItemIconTint;
+    private ColorStateList mItemTextColor;
+    private int mItemBackgroundRes;
+
+    private BottomNavigationPresenter mPresenter;
+    private MenuBuilder mMenu;
+
+    public BottomNavigationMenuView(Context context) {
+        this(context, null);
+    }
+
+    public BottomNavigationMenuView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final Resources res = getResources();
+        mInactiveItemMaxWidth = res.getDimensionPixelSize(
+                R.dimen.design_bottom_navigation_item_max_width);
+        mInactiveItemMinWidth = res.getDimensionPixelSize(
+                R.dimen.design_bottom_navigation_item_min_width);
+        mActiveItemMaxWidth = res.getDimensionPixelSize(
+                R.dimen.design_bottom_navigation_active_item_max_width);
+        mItemHeight = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_height);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            mAnimationHelper = new BottomNavigationAnimationHelperIcs();
+        } else {
+            mAnimationHelper = new BottomNavigationAnimationHelperBase();
+        }
+
+        mOnClickListener = new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                final BottomNavigationItemView itemView = (BottomNavigationItemView) v;
+                final int itemPosition = itemView.getItemPosition();
+                activateNewButton(itemPosition);
+                mMenu.performItemAction(itemView.getItemData(), mPresenter, 0);
+            }
+        };
+    }
+
+    @Override
+    public void initialize(MenuBuilder menu) {
+        mMenu = menu;
+        if (mMenu == null) return;
+        if (mMenu.size() > mActiveButton) {
+            mMenu.getItem(mActiveButton).setChecked(true);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int width = MeasureSpec.getSize(widthMeasureSpec);
+        final int count = getChildCount();
+
+        final int childState = 0;
+        final int heightSpec = MeasureSpec.makeMeasureSpec(mItemHeight, MeasureSpec.EXACTLY);
+
+        final int[] childWidths = new int[count];
+        if (mShiftingMode) {
+            final int inactiveCount = count - 1;
+            final int activeMaxAvailable = width - inactiveCount * mInactiveItemMinWidth;
+            final int activeWidth = Math.min(activeMaxAvailable, mActiveItemMaxWidth);
+            final int inactiveMaxAvailable = (width - activeWidth) / inactiveCount;
+            final int inactiveWidth = Math.min(inactiveMaxAvailable, mInactiveItemMaxWidth);
+            int extra = width - activeWidth - inactiveWidth * inactiveCount;
+            for (int i = 0; i < count; i++) {
+                childWidths[i] = (i == mActiveButton) ? activeWidth : inactiveWidth;
+                if (extra > 0) {
+                    childWidths[i]++;
+                    extra--;
+                }
+            }
+        } else {
+            final int maxAvailable = width / count;
+            final int childWidth = Math.min(maxAvailable, mActiveItemMaxWidth);
+            int extra = width - childWidth * count;
+            for (int i = 0; i < count; i++) {
+                childWidths[i] = childWidth;
+                if (extra > 0) {
+                    childWidths[i]++;
+                    extra--;
+                }
+            }
+        }
+
+        int totalWidth = 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            child.measure(MeasureSpec.makeMeasureSpec(childWidths[i], MeasureSpec.EXACTLY),
+                    heightSpec);
+            ViewGroup.LayoutParams params = child.getLayoutParams();
+            params.width = child.getMeasuredWidth();
+            totalWidth += child.getMeasuredWidth();
+        }
+        setMeasuredDimension(
+                ViewCompat.resolveSizeAndState(totalWidth,
+                        MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), childState),
+                ViewCompat.resolveSizeAndState(mItemHeight, heightSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int count = getChildCount();
+        final int width = right - left;
+        final int height = bottom - top;
+        int used = 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
+                child.layout(width - used - child.getMeasuredWidth(), 0, width - used, height);
+            } else {
+                child.layout(used, 0, child.getMeasuredWidth() + used, height);
+            }
+            used += child.getMeasuredWidth();
+        }
+    }
+
+    @Override
+    public int getWindowAnimations() {
+        return 0;
+    }
+
+    public void setIconTintList(ColorStateList color) {
+        mItemIconTint = color;
+        if (mButtons == null) return;
+        for (BottomNavigationItemView item : mButtons) {
+            item.setIconTintList(color);
+        }
+    }
+
+    @Nullable
+    public ColorStateList getIconTintList() {
+        return mItemIconTint;
+    }
+
+    public void setItemTextColor(ColorStateList color) {
+        mItemTextColor = color;
+        if (mButtons == null) return;
+        for (BottomNavigationItemView item : mButtons) {
+            item.setTextColor(color);
+        }
+    }
+
+    public ColorStateList getItemTextColor() {
+        return mItemTextColor;
+    }
+
+    public void setItemBackgroundRes(int background) {
+        mItemBackgroundRes = background;
+        if (mButtons == null) return;
+        for (BottomNavigationItemView item : mButtons) {
+            item.setItemBackground(background);
+        }
+    }
+
+    public int getItemBackgroundRes() {
+        return mItemBackgroundRes;
+    }
+
+    public void setPresenter(BottomNavigationPresenter presenter) {
+        mPresenter = presenter;
+    }
+
+    public void buildMenuView() {
+        if (mButtons != null) {
+            for (BottomNavigationItemView item : mButtons) {
+                sItemPool.release(item);
+            }
+        }
+        removeAllViews();
+        mButtons = new BottomNavigationItemView[mMenu.size()];
+        mShiftingMode = mMenu.size() > 3;
+        for (int i = 0; i < mMenu.size(); i++) {
+            mPresenter.setUpdateSuspended(true);
+            mMenu.getItem(i).setCheckable(true);
+            mPresenter.setUpdateSuspended(false);
+            BottomNavigationItemView child = getNewItem();
+            mButtons[i] = child;
+            child.setIconTintList(mItemIconTint);
+            child.setTextColor(mItemTextColor);
+            child.setItemBackground(mItemBackgroundRes);
+            child.setShiftingMode(mShiftingMode);
+            child.initialize((MenuItemImpl) mMenu.getItem(i), 0);
+            child.setItemPosition(i);
+            child.setOnClickListener(mOnClickListener);
+            addView(child);
+        }
+    }
+
+    public void updateMenuView() {
+        final int menuSize = mMenu.size();
+        if (menuSize != mButtons.length) {
+            // The size has changed. Rebuild menu view from scratch.
+            buildMenuView();
+            return;
+        }
+        for (int i = 0; i < menuSize; i++) {
+            mPresenter.setUpdateSuspended(true);
+            mButtons[i].initialize((MenuItemImpl) mMenu.getItem(i), 0);
+            mPresenter.setUpdateSuspended(false);
+        }
+    }
+
+    private void activateNewButton(int newButton) {
+        if (mActiveButton == newButton) return;
+
+        mAnimationHelper.beginDelayedTransition(this);
+
+        mPresenter.setUpdateSuspended(true);
+        mButtons[mActiveButton].setChecked(false);
+        mButtons[newButton].setChecked(true);
+        mPresenter.setUpdateSuspended(false);
+
+        mActiveButton = newButton;
+    }
+
+    private BottomNavigationItemView getNewItem() {
+        BottomNavigationItemView item = sItemPool.acquire();
+        if (item == null) {
+            item = new BottomNavigationItemView(getContext());
+        }
+        return item;
+    }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationPresenter.java b/design/src/android/support/design/internal/BottomNavigationPresenter.java
new file mode 100644
index 0000000..8dc0549
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationPresenter.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.view.menu.SubMenuBuilder;
+import android.view.ViewGroup;
+
+/**
+ * @hide
+ */
+public class BottomNavigationPresenter implements MenuPresenter {
+    private MenuBuilder mMenu;
+    private BottomNavigationMenuView mMenuView;
+    private boolean mUpdateSuspended = false;
+
+    public void setBottomNavigationMenuView(BottomNavigationMenuView menuView) {
+        mMenuView = menuView;
+    }
+
+    @Override
+    public void initForMenu(Context context, MenuBuilder menu) {
+        mMenuView.initialize(mMenu);
+        mMenu = menu;
+    }
+
+    @Override
+    public MenuView getMenuView(ViewGroup root) {
+        return mMenuView;
+    }
+
+    @Override
+    public void updateMenuView(boolean cleared) {
+        if (mUpdateSuspended) return;
+        if (cleared) {
+            mMenuView.buildMenuView();
+        } else {
+            mMenuView.updateMenuView();
+        }
+    }
+
+    @Override
+    public void setCallback(Callback cb) {}
+
+    @Override
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        return false;
+    }
+
+    @Override
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {}
+
+    @Override
+    public boolean flagActionItems() {
+        return false;
+    }
+
+    @Override
+    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    @Override
+    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    @Override
+    public int getId() {
+        return -1;
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        return null;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {}
+
+    public void setUpdateSuspended(boolean updateSuspended) {
+        mUpdateSuspended = updateSuspended;
+    }
+}
diff --git a/design/src/android/support/design/internal/NavigationMenuItemView.java b/design/src/android/support/design/internal/NavigationMenuItemView.java
index d1e6027..7b763ea 100644
--- a/design/src/android/support/design/internal/NavigationMenuItemView.java
+++ b/design/src/android/support/design/internal/NavigationMenuItemView.java
@@ -51,7 +51,7 @@
 
     private boolean mNeedsEmptyIcon;
 
-    private boolean mCheckable;
+    boolean mCheckable;
 
     private final CheckedTextView mTextView;
 
@@ -103,7 +103,7 @@
         setVisibility(itemData.isVisible() ? VISIBLE : GONE);
 
         if (getBackground() == null) {
-            setBackgroundDrawable(createDefaultBackground());
+            ViewCompat.setBackground(this, createDefaultBackground());
         }
 
         setCheckable(itemData.isCheckable());
@@ -250,8 +250,8 @@
         }
     }
 
-    public void setTextAppearance(Context context, int textAppearance) {
-        mTextView.setTextAppearance(context, textAppearance);
+    public void setTextAppearance(int textAppearance) {
+        TextViewCompat.setTextAppearance(mTextView, textAppearance);
     }
 
     public void setTextColor(ColorStateList colors) {
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index de2a7c5..c6f887e 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -55,20 +55,20 @@
     private static final String STATE_ADAPTER = "android:menu:adapter";
 
     private NavigationMenuView mMenuView;
-    private LinearLayout mHeaderLayout;
+    LinearLayout mHeaderLayout;
 
     private Callback mCallback;
-    private MenuBuilder mMenu;
+    MenuBuilder mMenu;
     private int mId;
 
-    private NavigationMenuAdapter mAdapter;
-    private LayoutInflater mLayoutInflater;
+    NavigationMenuAdapter mAdapter;
+    LayoutInflater mLayoutInflater;
 
-    private int mTextAppearance;
-    private boolean mTextAppearanceSet;
-    private ColorStateList mTextColor;
-    private ColorStateList mIconTintList;
-    private Drawable mItemBackground;
+    int mTextAppearance;
+    boolean mTextAppearanceSet;
+    ColorStateList mTextColor;
+    ColorStateList mIconTintList;
+    Drawable mItemBackground;
 
     /**
      * Padding to be inserted at the top of the list to avoid the first menu item
@@ -79,7 +79,7 @@
     /**
      * Padding for separators between items
      */
-    private int mPaddingSeparator;
+    int mPaddingSeparator;
 
     @Override
     public void initForMenu(Context context, MenuBuilder menu) {
@@ -318,7 +318,7 @@
     /**
      * Handles click events for the menu items. The items has to be {@link NavigationMenuItemView}.
      */
-    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+    final View.OnClickListener mOnClickListener = new View.OnClickListener() {
 
         @Override
         public void onClick(View v) {
@@ -403,12 +403,12 @@
                     NavigationMenuItemView itemView = (NavigationMenuItemView) holder.itemView;
                     itemView.setIconTintList(mIconTintList);
                     if (mTextAppearanceSet) {
-                        itemView.setTextAppearance(itemView.getContext(), mTextAppearance);
+                        itemView.setTextAppearance(mTextAppearance);
                     }
                     if (mTextColor != null) {
                         itemView.setTextColor(mTextColor);
                     }
-                    itemView.setBackgroundDrawable(mItemBackground != null ?
+                    ViewCompat.setBackground(itemView, mItemBackground != null ?
                             mItemBackground.getConstantState().newDrawable() : null);
                     NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
                     itemView.setNeedsEmptyIcon(item.needsEmptyIcon);
@@ -612,7 +612,7 @@
 
         boolean needsEmptyIcon;
 
-        private NavigationMenuTextItem(MenuItemImpl item) {
+        NavigationMenuTextItem(MenuItemImpl item) {
             mMenuItem = item;
         }
 
@@ -650,6 +650,8 @@
      * Header (not subheader) items.
      */
     private static class NavigationMenuHeaderItem implements NavigationMenuItem {
+        NavigationMenuHeaderItem() {
+        }
         // The actual content is hold by NavigationMenuPresenter#mHeaderLayout.
     }
 
diff --git a/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java b/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
index 80aee76..34d3a79 100644
--- a/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
+++ b/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
@@ -34,9 +34,9 @@
  */
 public class ScrimInsetsFrameLayout extends FrameLayout {
 
-    private Drawable mInsetForeground;
+    Drawable mInsetForeground;
 
-    private Rect mInsets;
+    Rect mInsets;
 
     private Rect mTempRect = new Rect();
 
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
index c253029..9aadd86 100644
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ b/design/src/android/support/design/widget/AppBarLayout.java
@@ -103,10 +103,10 @@
 @CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
 public class AppBarLayout extends LinearLayout {
 
-    private static final int PENDING_ACTION_NONE = 0x0;
-    private static final int PENDING_ACTION_EXPANDED = 0x1;
-    private static final int PENDING_ACTION_COLLAPSED = 0x2;
-    private static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
+    static final int PENDING_ACTION_NONE = 0x0;
+    static final int PENDING_ACTION_EXPANDED = 0x1;
+    static final int PENDING_ACTION_COLLAPSED = 0x2;
+    static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
 
     /**
      * Interface definition for a callback to be invoked when an {@link AppBarLayout}'s vertical
@@ -166,7 +166,7 @@
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
                 0, R.style.Widget_Design_AppBarLayout);
-        setBackgroundDrawable(a.getDrawable(R.styleable.AppBarLayout_android_background));
+        ViewCompat.setBackground(this, a.getDrawable(R.styleable.AppBarLayout_android_background));
         if (a.hasValue(R.styleable.AppBarLayout_expanded)) {
             setExpanded(a.getBoolean(R.styleable.AppBarLayout_expanded, false));
         }
@@ -325,7 +325,7 @@
         return new LayoutParams(p);
     }
 
-    private boolean hasChildWithInterpolator() {
+    boolean hasChildWithInterpolator() {
         return mHaveChildWithInterpolator;
     }
 
@@ -366,21 +366,21 @@
         return mTotalScrollRange = Math.max(0, range - getTopInset());
     }
 
-    private boolean hasScrollableChildren() {
+    boolean hasScrollableChildren() {
         return getTotalScrollRange() != 0;
     }
 
     /**
      * Return the scroll range when scrolling up from a nested pre-scroll.
      */
-    private int getUpNestedPreScrollRange() {
+    int getUpNestedPreScrollRange() {
         return getTotalScrollRange();
     }
 
     /**
      * Return the scroll range when scrolling down from a nested pre-scroll.
      */
-    private int getDownNestedPreScrollRange() {
+    int getDownNestedPreScrollRange() {
         if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
             // If we already have a valid value, return it
             return mDownPreScrollRange;
@@ -419,7 +419,7 @@
     /**
      * Return the scroll range when scrolling down from a nested scroll.
      */
-    private int getDownNestedScrollRange() {
+    int getDownNestedScrollRange() {
         if (mDownScrollRange != INVALID_SCROLL_RANGE) {
             // If we already have a valid value, return it
             return mDownScrollRange;
@@ -454,7 +454,7 @@
         return mDownScrollRange = Math.max(0, range);
     }
 
-    private void dispatchOffsetUpdates(int offset) {
+    void dispatchOffsetUpdates(int offset) {
         // Iterate backwards through the list so that most recently added listeners
         // get the first chance to decide
         if (mListeners != null) {
@@ -519,7 +519,7 @@
      *
      * @return true if the collapsed state changed
      */
-    private boolean setCollapsedState(boolean collapsed) {
+    boolean setCollapsedState(boolean collapsed) {
         if (mCollapsed != collapsed) {
             mCollapsed = collapsed;
             refreshDrawableState();
@@ -553,11 +553,11 @@
         return 0;
     }
 
-    private int getPendingAction() {
+    int getPendingAction() {
         return mPendingAction;
     }
 
-    private void resetPendingAction() {
+    void resetPendingAction() {
         mPendingAction = PENDING_ACTION_NONE;
     }
 
@@ -566,7 +566,7 @@
         return mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
     }
 
-    private WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
+    WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
         WindowInsetsCompat newInsets = null;
 
         if (ViewCompat.getFitsSystemWindows(this)) {
@@ -742,7 +742,7 @@
         /**
          * Returns true if the scroll flags are compatible for 'collapsing'
          */
-        private boolean isCollapsible() {
+        boolean isCollapsible() {
             return (mScrollFlags & SCROLL_FLAG_SCROLL) == SCROLL_FLAG_SCROLL
                     && (mScrollFlags & COLLAPSIBLE_FLAGS) != 0;
         }
diff --git a/design/src/android/support/design/widget/BottomNavigationView.java b/design/src/android/support/design/widget/BottomNavigationView.java
new file mode 100644
index 0000000..476889f
--- /dev/null
+++ b/design/src/android/support/design/widget/BottomNavigationView.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.design.R;
+import android.support.design.internal.BottomNavigationMenu;
+import android.support.design.internal.BottomNavigationMenuView;
+import android.support.design.internal.BottomNavigationPresenter;
+import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.widget.TintTypedArray;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+/**
+ * <p>
+ * Represents a standard bottom navigation bar for application. It is an implementation of
+ * <a href="https://material.google.com/components/bottom-navigation.html">material design bottom
+ * navigation</a>.
+ * </p>
+ *
+ * <p>
+ * Bottom navigation bars make it easy for users to explore and switch between top-level views in
+ * a single tap. It should be used when application has three to five top-level destinations.
+ * </p>
+ *
+ * <p>
+ * The bar contents can be populated by specifying a menu resource file. Each menu item title, icon
+ * and enabled state will be used for displaying bottom navigation bar items.
+ * </p>
+ *
+ * <pre>
+ * &lt;android.support.design.widget.BottomNavigationView
+ *     xmlns:android="http://schemas.android.com/apk/res/android"
+ *     xmlns:design="http://schema.android.com/apk/res/android.support.design"
+ *     android:id="@+id/navigation"
+ *     android:layout_width="wrap_content"
+ *     android:layout_height="match_parent"
+ *     android:layout_gravity="start"
+ *     design:menu="@menu/my_navigation_items" /&gt;
+ * </pre>
+ */
+public class BottomNavigationView extends FrameLayout {
+
+    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
+    private static final int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled};
+
+    private final MenuBuilder mMenu;
+    private final BottomNavigationMenuView mMenuView;
+    private final BottomNavigationPresenter mPresenter = new BottomNavigationPresenter();
+    private MenuInflater mMenuInflater;
+
+    private OnNavigationItemSelectedListener mListener;
+
+    public BottomNavigationView(Context context) {
+        this(context, null);
+    }
+
+    public BottomNavigationView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        ThemeUtils.checkAppCompatTheme(context);
+
+        // Create the menu
+        mMenu = new BottomNavigationMenu(context);
+
+        mMenuView = new BottomNavigationMenuView(context);
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        params.gravity = Gravity.CENTER;
+        mMenuView.setLayoutParams(params);
+
+        mPresenter.setBottomNavigationMenuView(mMenuView);
+        mMenuView.setPresenter(mPresenter);
+        mMenu.addMenuPresenter(mPresenter);
+
+
+        // Custom attributes
+        TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
+                R.styleable.BottomNavigationView, defStyleAttr,
+                R.style.Widget_Design_BottomNavigationView);
+
+        if (a.hasValue(R.styleable.BottomNavigationView_itemIconTint)) {
+            mMenuView.setIconTintList(
+                    a.getColorStateList(R.styleable.BottomNavigationView_itemIconTint));
+        } else {
+            mMenuView.setIconTintList(
+                    createDefaultColorStateList(android.R.attr.textColorSecondary));
+        }
+        if (a.hasValue(R.styleable.BottomNavigationView_itemTextColor)) {
+            mMenuView.setItemTextColor(
+                    a.getColorStateList(R.styleable.BottomNavigationView_itemTextColor));
+        } else {
+            mMenuView.setItemTextColor(
+                    createDefaultColorStateList(android.R.attr.textColorSecondary));
+        }
+
+        int itemBackground = a.getResourceId(R.styleable.BottomNavigationView_itemBackground, 0);
+        mMenuView.setItemBackgroundRes(itemBackground);
+
+        if (a.hasValue(R.styleable.BottomNavigationView_menu)) {
+            inflateMenu(a.getResourceId(R.styleable.BottomNavigationView_menu, 0));
+        }
+        a.recycle();
+
+        addView(mMenuView, params);
+
+        mMenu.setCallback(new MenuBuilder.Callback() {
+            @Override
+            public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+                return mListener != null && mListener.onNavigationItemSelected(item);
+            }
+
+            @Override
+            public void onMenuModeChange(MenuBuilder menu) {}
+        });
+    }
+
+    /**
+     * Set a listener that will be notified when a bottom navigation item is selected.
+     *
+     * @param listener The listener to notify
+     */
+    public void setOnNavigationItemSelectedListener(
+            @Nullable OnNavigationItemSelectedListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Returns the {@link Menu} instance associated with this bottom navigation bar.
+     */
+    @NonNull
+    public Menu getMenu() {
+        return mMenu;
+    }
+
+    /**
+     * Inflate a menu resource into this navigation view.
+     *
+     * <p>Existing items in the menu will not be modified or removed.</p>
+     *
+     * @param resId ID of a menu resource to inflate
+     */
+    public void inflateMenu(int resId) {
+        mPresenter.setUpdateSuspended(true);
+        getMenuInflater().inflate(resId, mMenu);
+        mPresenter.initForMenu(getContext(), mMenu);
+        mPresenter.setUpdateSuspended(false);
+        mPresenter.updateMenuView(true);
+    }
+
+    /**
+     * @return The maximum number of items that can be shown in BottomNavigationView.
+     */
+    public int getMaxItemCount() {
+        return BottomNavigationMenu.MAX_ITEM_COUNT;
+    }
+
+    /**
+     * Returns the tint which is applied to our menu items' icons.
+     *
+     * @see #setItemIconTintList(ColorStateList)
+     *
+     * @attr ref R.styleable#BottomNavigationView_itemIconTint
+     */
+    @Nullable
+    public ColorStateList getItemIconTintList() {
+        return mMenuView.getIconTintList();
+    }
+
+    /**
+     * Set the tint which is applied to our menu items' icons.
+     *
+     * @param tint the tint to apply.
+     *
+     * @attr ref R.styleable#BottomNavigationView_itemIconTint
+     */
+    public void setItemIconTintList(@Nullable ColorStateList tint) {
+        mMenuView.setIconTintList(tint);
+    }
+
+    /**
+     * Returns the tint which is applied to menu items' icons.
+     *
+     * @see #setItemTextColor(ColorStateList)
+     *
+     * @attr ref R.styleable#BottomNavigationView_itemTextColor
+     */
+    @Nullable
+    public ColorStateList getItemTextColor() {
+        return mMenuView.getItemTextColor();
+    }
+
+    /**
+     * Set the text color to be used on menu items.
+     *
+     * @see #getItemTextColor()
+     *
+     * @attr ref R.styleable#BottomNavigationView_itemTextColor
+     */
+    public void setItemTextColor(@Nullable ColorStateList textColor) {
+        mMenuView.setItemTextColor(textColor);
+    }
+
+    /**
+     * Returns the background resource of the menu items.
+     *
+     * @see #setItemBackgroundResource(int)
+     *
+     * @attr ref R.styleable#BottomNavigationView_itemBackground
+     */
+    @DrawableRes
+    public int getItemBackgroundResource() {
+        return mMenuView.getItemBackgroundRes();
+    }
+
+    /**
+     * Set the background of our menu items to the given resource.
+     *
+     * @param resId The identifier of the resource.
+     *
+     * @attr ref R.styleable#BottomNavigationView_itemBackground
+     */
+    public void setItemBackgroundResource(@DrawableRes int resId) {
+        mMenuView.setItemBackgroundRes(resId);
+    }
+
+    /**
+     * Listener for handling events on bottom navigation items.
+     */
+    public interface OnNavigationItemSelectedListener {
+
+        /**
+         * Called when an item in the bottom navigation menu is selected.
+         *
+         * @param item The selected item
+         *
+         * @return true to display the item as the selected item
+         */
+        boolean onNavigationItemSelected(@NonNull MenuItem item);
+    }
+
+    private MenuInflater getMenuInflater() {
+        if (mMenuInflater == null) {
+            mMenuInflater = new SupportMenuInflater(getContext());
+        }
+        return mMenuInflater;
+    }
+
+    private ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {
+        final TypedValue value = new TypedValue();
+        if (!getContext().getTheme().resolveAttribute(baseColorThemeAttr, value, true)) {
+            return null;
+        }
+        ColorStateList baseColor = AppCompatResources.getColorStateList(
+                getContext(), value.resourceId);
+        if (!getContext().getTheme().resolveAttribute(
+                android.support.v7.appcompat.R.attr.colorPrimary, value, true)) {
+            return null;
+        }
+        int colorPrimary = value.data;
+        int defaultColor = baseColor.getDefaultColor();
+        return new ColorStateList(new int[][]{
+                DISABLED_STATE_SET,
+                CHECKED_STATE_SET,
+                EMPTY_STATE_SET
+        }, new int[]{
+                baseColor.getColorForState(DISABLED_STATE_SET, defaultColor),
+                colorPrimary,
+                defaultColor
+        });
+    }
+}
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
index 1337352..222e0f6 100644
--- a/design/src/android/support/design/widget/BottomSheetBehavior.java
+++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
@@ -22,6 +22,7 @@
 import android.os.Parcelable;
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
 import android.support.design.R;
 import android.support.v4.os.ParcelableCompat;
 import android.support.v4.os.ParcelableCompatCreatorCallbacks;
@@ -128,18 +129,18 @@
 
     private int mPeekHeightMin;
 
-    private int mMinOffset;
+    int mMinOffset;
 
-    private int mMaxOffset;
+    int mMaxOffset;
 
-    private boolean mHideable;
+    boolean mHideable;
 
     private boolean mSkipCollapsed;
 
     @State
-    private int mState = STATE_COLLAPSED;
+    int mState = STATE_COLLAPSED;
 
-    private ViewDragHelper mViewDragHelper;
+    ViewDragHelper mViewDragHelper;
 
     private boolean mIgnoreEvents;
 
@@ -147,21 +148,21 @@
 
     private boolean mNestedScrolled;
 
-    private int mParentHeight;
+    int mParentHeight;
 
-    private WeakReference<V> mViewRef;
+    WeakReference<V> mViewRef;
 
-    private WeakReference<View> mNestedScrollingChildRef;
+    WeakReference<View> mNestedScrollingChildRef;
 
     private BottomSheetCallback mCallback;
 
     private VelocityTracker mVelocityTracker;
 
-    private int mActivePointerId;
+    int mActivePointerId;
 
     private int mInitialY;
 
-    private boolean mTouchingScrollingChild;
+    boolean mTouchingScrollingChild;
 
     /**
      * Default constructor for instantiating BottomSheetBehaviors.
@@ -253,6 +254,7 @@
     @Override
     public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
         if (!child.isShown()) {
+            mIgnoreEvents = true;
             return false;
         }
         int action = MotionEventCompat.getActionMasked(event);
@@ -560,7 +562,7 @@
         return mState;
     }
 
-    private void setStateInternal(@State int state) {
+    void setStateInternal(@State int state) {
         if (mState == state) {
             return;
         }
@@ -579,7 +581,7 @@
         }
     }
 
-    private boolean shouldHide(View child, float yvel) {
+    boolean shouldHide(View child, float yvel) {
         if (mSkipCollapsed) {
             return true;
         }
@@ -612,7 +614,7 @@
         return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId);
     }
 
-    private void startSettlingAnimation(View child, int state) {
+    void startSettlingAnimation(View child, int state) {
         int top;
         if (state == STATE_COLLAPSED) {
             top = mMaxOffset;
@@ -713,7 +715,7 @@
         }
     };
 
-    private void dispatchOnSlide(int top) {
+    void dispatchOnSlide(int top) {
         View bottomSheet = mViewRef.get();
         if (bottomSheet != null && mCallback != null) {
             if (top > mMaxOffset) {
@@ -725,6 +727,11 @@
         }
     }
 
+    @VisibleForTesting
+    int getPeekHeightMin() {
+        return mPeekHeightMin;
+    }
+
     private class SettleRunnable implements Runnable {
 
         private final View mView;
diff --git a/design/src/android/support/design/widget/BottomSheetDialog.java b/design/src/android/support/design/widget/BottomSheetDialog.java
index 0473e54..4c124f3 100644
--- a/design/src/android/support/design/widget/BottomSheetDialog.java
+++ b/design/src/android/support/design/widget/BottomSheetDialog.java
@@ -38,7 +38,7 @@
 
     private BottomSheetBehavior<FrameLayout> mBehavior;
 
-    private boolean mCancelable = true;
+    boolean mCancelable = true;
     private boolean mCanceledOnTouchOutside = true;
     private boolean mCanceledOnTouchOutsideSet;
 
@@ -130,7 +130,7 @@
         return coordinator;
     }
 
-    private boolean shouldWindowCloseOnTouchOutside() {
+    boolean shouldWindowCloseOnTouchOutside() {
         if (!mCanceledOnTouchOutsideSet) {
             if (Build.VERSION.SDK_INT < 11) {
                 mCanceledOnTouchOutside = true;
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
index 6d95dec..b969af7 100644
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
@@ -114,12 +114,12 @@
     private int mExpandedMarginBottom;
 
     private final Rect mTmpRect = new Rect();
-    private final CollapsingTextHelper mCollapsingTextHelper;
+    final CollapsingTextHelper mCollapsingTextHelper;
     private boolean mCollapsingTitleEnabled;
     private boolean mDrawCollapsingTitle;
 
     private Drawable mContentScrim;
-    private Drawable mStatusBarScrim;
+    Drawable mStatusBarScrim;
     private int mScrimAlpha;
     private boolean mScrimsAreShown;
     private ValueAnimatorCompat mScrimAnimator;
@@ -128,9 +128,9 @@
 
     private AppBarLayout.OnOffsetChangedListener mOnOffsetChangedListener;
 
-    private int mCurrentOffset;
+    int mCurrentOffset;
 
-    private WindowInsetsCompat mLastInsets;
+    WindowInsetsCompat mLastInsets;
 
     public CollapsingToolbarLayout(Context context) {
         this(context, null);
@@ -258,7 +258,7 @@
         super.onDetachedFromWindow();
     }
 
-    private WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
+    WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
         WindowInsetsCompat newInsets = null;
 
         if (ViewCompat.getFitsSystemWindows(this)) {
@@ -272,7 +272,9 @@
             requestLayout();
         }
 
-        return insets;
+        // Consume the insets. This is done so that child views with fitSystemWindows=true do not
+        // get the default padding functionality from View
+        return insets.consumeSystemWindowInsets();
     }
 
     @Override
@@ -490,7 +492,7 @@
         return view.getHeight();
     }
 
-    private static ViewOffsetHelper getViewOffsetHelper(View view) {
+    static ViewOffsetHelper getViewOffsetHelper(View view) {
         ViewOffsetHelper offsetHelper = (ViewOffsetHelper) view.getTag(R.id.view_offset_helper);
         if (offsetHelper == null) {
             offsetHelper = new ViewOffsetHelper(view);
@@ -609,7 +611,7 @@
         mScrimAnimator.start();
     }
 
-    private void setScrimAlpha(int alpha) {
+    void setScrimAlpha(int alpha) {
         if (alpha != mScrimAlpha) {
             final Drawable contentScrim = mContentScrim;
             if (contentScrim != null && mToolbar != null) {
@@ -1050,7 +1052,7 @@
      * Returns the amount of visible height in pixels used to define when to trigger a scrim
      * visibility change.
      *
-     * @see #setScrimTriggerOffset(int)
+     * @see #setScrimVisibleHeightTrigger(int)
      */
     public int getScrimVisibleHeightTrigger() {
         if (mScrimVisibleHeightTrigger >= 0) {
@@ -1241,6 +1243,9 @@
     }
 
     private class OffsetUpdateListener implements AppBarLayout.OnOffsetChangedListener {
+        OffsetUpdateListener() {
+        }
+
         @Override
         public void onOffsetChanged(AppBarLayout layout, int verticalOffset) {
             mCurrentOffset = verticalOffset;
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index 201ed9b..dbcfabb 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -132,9 +132,9 @@
             new ThreadLocal<>();
 
 
-    private static final int EVENT_PRE_DRAW = 0;
-    private static final int EVENT_NESTED_SCROLL = 1;
-    private static final int EVENT_VIEW_REMOVED = 2;
+    static final int EVENT_PRE_DRAW = 0;
+    static final int EVENT_NESTED_SCROLL = 1;
+    static final int EVENT_VIEW_REMOVED = 2;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -172,7 +172,7 @@
     private boolean mDrawStatusBarBackground;
     private Drawable mStatusBarBackground;
 
-    private OnHierarchyChangeListener mOnHierarchyChangeListener;
+    OnHierarchyChangeListener mOnHierarchyChangeListener;
     private android.support.v4.view.OnApplyWindowInsetsListener mApplyWindowInsetsListener;
 
     private final NestedScrollingParentHelper mNestedScrollingParentHelper =
@@ -624,13 +624,7 @@
         return result;
     }
 
-    private void prepareChildren(final boolean forceRefresh) {
-        if (!forceRefresh && mChildDag.size() == getChildCount()
-                && mChildDag.size() == mDependencySortedChildren.size()) {
-            // If we're not being forced and everything looks good, lets skip the call
-            return;
-        }
-
+    private void prepareChildren() {
         mDependencySortedChildren.clear();
         mChildDag.clear();
 
@@ -709,7 +703,7 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        prepareChildren(true);
+        prepareChildren();
         ensurePreDrawListener();
 
         final int paddingLeft = getPaddingLeft();
@@ -1395,12 +1389,10 @@
      * @param view the View to find dependents of to dispatch the call.
      */
     public void dispatchDependentViewsChanged(View view) {
-        prepareChildren(false);
-
         final List<View> dependents = mChildDag.getIncomingEdges(view);
         if (dependents != null && !dependents.isEmpty()) {
             for (int i = 0; i < dependents.size(); i++) {
-                final View child = (View) dependents.get(i);
+                final View child = dependents.get(i);
                 CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)
                         child.getLayoutParams();
                 CoordinatorLayout.Behavior b = lp.getBehavior();
@@ -1421,8 +1413,6 @@
      */
     @NonNull
     public List<View> getDependencies(@NonNull View child) {
-        prepareChildren(false);
-
         final List<View> dependencies = mChildDag.getOutgoingEdges(child);
         mTempDependenciesList.clear();
         if (dependencies != null) {
@@ -1441,8 +1431,6 @@
      */
     @NonNull
     public List<View> getDependents(@NonNull View child) {
-        prepareChildren(false);
-
         final List<View> edges = mChildDag.getIncomingEdges(child);
         mTempDependenciesList.clear();
         if (edges != null) {
@@ -1453,7 +1441,7 @@
 
     @VisibleForTesting
     final List<View> getDependencySortedChildren() {
-        prepareChildren(true);
+        prepareChildren();
         return Collections.unmodifiableList(mDependencySortedChildren);
     }
 
@@ -1483,8 +1471,7 @@
     /**
      * Check if the given child has any layout dependencies on other child views.
      */
-    boolean hasDependencies(View child) {
-        prepareChildren(false);
+    private boolean hasDependencies(View child) {
         return mChildDag.hasOutgoingEdges(child);
     }
 
@@ -2502,8 +2489,8 @@
          */
         public int dodgeInsetEdges = Gravity.NO_GRAVITY;
 
-        private int mInsetOffsetX;
-        private int mInsetOffsetY;
+        int mInsetOffsetX;
+        int mInsetOffsetY;
 
         View mAnchorView;
         View mAnchorDirectChild;
@@ -2851,6 +2838,9 @@
     }
 
     private class HierarchyChangeListener implements OnHierarchyChangeListener {
+        HierarchyChangeListener() {
+        }
+
         @Override
         public void onChildViewAdded(View parent, View child) {
             if (mOnHierarchyChangeListener != null) {
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 68b7c5b..eb379b9 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -130,11 +130,11 @@
     private int mBorderWidth;
     private int mRippleColor;
     private int mSize;
-    private int mImagePadding;
+    int mImagePadding;
     private int mMaxImageSize;
 
-    private boolean mCompatPadding;
-    private final Rect mShadowPadding = new Rect();
+    boolean mCompatPadding;
+    final Rect mShadowPadding = new Rect();
     private final Rect mTouchArea = new Rect();
 
     private AppCompatImageHelper mImageHelper;
@@ -201,13 +201,25 @@
     }
 
     /**
-     * Set the ripple color for this {@link FloatingActionButton}.
-     * <p>
-     * When running on devices with KitKat or below, we draw a fill rather than a ripple.
+     * Returns the ripple color for this button.
      *
-     * @param color ARGB color to use for the ripple.
+     * @return the ARGB color used for the ripple
+     * @see #setRippleColor(int)
+     */
+    @ColorInt
+    public int getRippleColor() {
+        return mRippleColor;
+    }
+
+    /**
+     * Sets the ripple color for this button.
      *
+     * <p>When running on devices with KitKat or below, we draw this color as a filled circle
+     * rather than a ripple.</p>
+     *
+     * @param color ARGB color to use for the ripple
      * @attr ref android.support.design.R.styleable#FloatingActionButton_rippleColor
+     * @see #getRippleColor()
      */
     public void setRippleColor(@ColorInt int color) {
         if (mRippleColor != color) {
@@ -217,7 +229,7 @@
     }
 
     /**
-     * Return the tint applied to the background drawable, if specified.
+     * Returns the tint applied to the background drawable, if specified.
      *
      * @return the tint applied to the background drawable
      * @see #setBackgroundTintList(ColorStateList)
@@ -242,7 +254,7 @@
     }
 
     /**
-     * Return the blending mode used to apply the tint to the background
+     * Returns the blending mode used to apply the tint to the background
      * drawable, if specified.
      *
      * @return the blending mode used to apply the tint to the background
@@ -309,7 +321,7 @@
         show(listener, true);
     }
 
-    private void show(OnVisibilityChangedListener listener, boolean fromUser) {
+    void show(OnVisibilityChangedListener listener, boolean fromUser) {
         getImpl().show(wrapOnVisibilityChangedListener(listener), fromUser);
     }
 
@@ -331,7 +343,7 @@
         hide(listener, true);
     }
 
-    private void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
+    void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
         getImpl().hide(wrapOnVisibilityChangedListener(listener), fromUser);
     }
 
@@ -414,7 +426,7 @@
         };
     }
 
-    private int getSizeDimension() {
+    int getSizeDimension() {
         return getSizeDimension(mSize);
     }
 
@@ -790,6 +802,9 @@
     }
 
     private class ShadowDelegateImpl implements ShadowViewDelegate {
+        ShadowDelegateImpl() {
+        }
+
         @Override
         public float getRadius() {
             return getSizeDimension() / 2f;
diff --git a/design/src/android/support/design/widget/HeaderBehavior.java b/design/src/android/support/design/widget/HeaderBehavior.java
index 7dd2700..5e555de 100644
--- a/design/src/android/support/design/widget/HeaderBehavior.java
+++ b/design/src/android/support/design/widget/HeaderBehavior.java
@@ -37,7 +37,7 @@
     private static final int INVALID_POINTER = -1;
 
     private Runnable mFlingRunnable;
-    private ScrollerCompat mScroller;
+    ScrollerCompat mScroller;
 
     private boolean mIsBeingDragged;
     private int mActivePointerId = INVALID_POINTER;
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index e53b7e8..428b565 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -84,7 +84,7 @@
     private final NavigationMenu mMenu;
     private final NavigationMenuPresenter mPresenter = new NavigationMenuPresenter();
 
-    private OnNavigationItemSelectedListener mListener;
+    OnNavigationItemSelectedListener mListener;
     private int mMaxWidth;
 
     private MenuInflater mMenuInflater;
@@ -110,8 +110,8 @@
                 R.styleable.NavigationView, defStyleAttr,
                 R.style.Widget_Design_NavigationView);
 
-        //noinspection deprecation
-        setBackgroundDrawable(a.getDrawable(R.styleable.NavigationView_android_background));
+        ViewCompat.setBackground(
+                this, a.getDrawable(R.styleable.NavigationView_android_background));
         if (a.hasValue(R.styleable.NavigationView_elevation)) {
             ViewCompat.setElevation(this, a.getDimensionPixelSize(
                     R.styleable.NavigationView_elevation, 0));
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index bc5df7f..2c87529 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -154,9 +154,9 @@
     static final int ANIMATION_DURATION = 250;
     static final int ANIMATION_FADE_DURATION = 180;
 
-    private static final Handler sHandler;
-    private static final int MSG_SHOW = 0;
-    private static final int MSG_DISMISS = 1;
+    static final Handler sHandler;
+    static final int MSG_SHOW = 0;
+    static final int MSG_DISMISS = 1;
 
     static {
         sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@@ -177,7 +177,7 @@
 
     private final ViewGroup mTargetParent;
     private final Context mContext;
-    private final SnackbarLayout mView;
+    final SnackbarLayout mView;
     private int mDuration;
     private Callback mCallback;
 
@@ -401,7 +401,7 @@
         dispatchDismiss(Callback.DISMISS_EVENT_MANUAL);
     }
 
-    private void dispatchDismiss(@Callback.DismissEvent int event) {
+    void dispatchDismiss(@Callback.DismissEvent int event) {
         SnackbarManager.getInstance().dismiss(mManagerCallback, event);
     }
 
@@ -429,7 +429,7 @@
         return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback);
     }
 
-    private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
+    final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
         @Override
         public void show() {
             sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, Snackbar.this));
@@ -531,7 +531,7 @@
         }
     }
 
-    private void animateViewIn() {
+    void animateViewIn() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
             ViewCompat.setTranslationY(mView, mView.getHeight());
             ViewCompat.animate(mView)
@@ -618,14 +618,14 @@
         }
     }
 
-    private void onViewShown() {
+    void onViewShown() {
         SnackbarManager.getInstance().onShown(mManagerCallback);
         if (mCallback != null) {
             mCallback.onShown(this);
         }
     }
 
-    private void onViewHidden(int event) {
+    void onViewHidden(int event) {
         // First tell the SnackbarManager that it has been dismissed
         SnackbarManager.getInstance().onDismissed(mManagerCallback);
         // Now call the dismiss listener (if available)
@@ -650,7 +650,7 @@
     /**
      * Returns true if we should animate the Snackbar view in/out.
      */
-    private boolean shouldAnimate() {
+    boolean shouldAnimate() {
         return !mAccessibilityManager.isEnabled();
     }
 
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
index e0c3922..b391a3a 100644
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ b/design/src/android/support/design/widget/SnackbarManager.java
@@ -27,7 +27,7 @@
  */
 class SnackbarManager {
 
-    private static final int MSG_TIMEOUT = 0;
+    static final int MSG_TIMEOUT = 0;
 
     private static final int SHORT_DURATION_MS = 1500;
     private static final int LONG_DURATION_MS = 2750;
@@ -166,8 +166,8 @@
     }
 
     private static class SnackbarRecord {
-        private final WeakReference<Callback> callback;
-        private int duration;
+        final WeakReference<Callback> callback;
+        int duration;
 
         SnackbarRecord(int duration, Callback callback) {
             this.callback = new WeakReference<>(callback);
@@ -229,7 +229,7 @@
         mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_TIMEOUT, r), durationMs);
     }
 
-    private void handleTimeout(SnackbarRecord record) {
+    void handleTimeout(SnackbarRecord record) {
         synchronized (mLock) {
             if (mCurrentSnackbar == record || mNextSnackbar == record) {
                 cancelSnackbarLocked(record, Snackbar.Callback.DISMISS_EVENT_TIMEOUT);
diff --git a/design/src/android/support/design/widget/SwipeDismissBehavior.java b/design/src/android/support/design/widget/SwipeDismissBehavior.java
index ae1ef86..c2e02cd 100644
--- a/design/src/android/support/design/widget/SwipeDismissBehavior.java
+++ b/design/src/android/support/design/widget/SwipeDismissBehavior.java
@@ -78,17 +78,17 @@
     private static final float DEFAULT_ALPHA_START_DISTANCE = 0f;
     private static final float DEFAULT_ALPHA_END_DISTANCE = DEFAULT_DRAG_DISMISS_THRESHOLD;
 
-    private ViewDragHelper mViewDragHelper;
-    private OnDismissListener mListener;
+    ViewDragHelper mViewDragHelper;
+    OnDismissListener mListener;
     private boolean mInterceptingEvents;
 
     private float mSensitivity = 0f;
     private boolean mSensitivitySet;
 
-    private int mSwipeDirection = SWIPE_DIRECTION_ANY;
-    private float mDragDismissThreshold = DEFAULT_DRAG_DISMISS_THRESHOLD;
-    private float mAlphaStartSwipeDistance = DEFAULT_ALPHA_START_DISTANCE;
-    private float mAlphaEndSwipeDistance = DEFAULT_ALPHA_END_DISTANCE;
+    int mSwipeDirection = SWIPE_DIRECTION_ANY;
+    float mDragDismissThreshold = DEFAULT_DRAG_DISMISS_THRESHOLD;
+    float mAlphaStartSwipeDistance = DEFAULT_ALPHA_START_DISTANCE;
+    float mAlphaEndSwipeDistance = DEFAULT_ALPHA_END_DISTANCE;
 
     /**
      * Callback interface used to notify the application that the view has been dismissed.
@@ -381,11 +381,11 @@
         }
     }
 
-    private static float clamp(float min, float value, float max) {
+    static float clamp(float min, float value, float max) {
         return Math.min(Math.max(min, value), max);
     }
 
-    private static int clamp(int min, int value, int max) {
+    static int clamp(int min, int value, int max) {
         return Math.min(Math.max(min, value), max);
     }
 
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 01ca835..4b8ccf8 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -53,6 +53,7 @@
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -144,12 +145,12 @@
 public class TabLayout extends HorizontalScrollView {
 
     private static final int DEFAULT_HEIGHT_WITH_TEXT_ICON = 72; // dps
-    private static final int DEFAULT_GAP_TEXT_ICON = 8; // dps
+    static final int DEFAULT_GAP_TEXT_ICON = 8; // dps
     private static final int INVALID_WIDTH = -1;
     private static final int DEFAULT_HEIGHT = 48; // dps
     private static final int TAB_MIN_WIDTH_MARGIN = 56; //dps
-    private static final int FIXED_WRAP_GUTTER_MIN = 16; //dps
-    private static final int MOTION_NON_ADJACENT_OFFSET = 24;
+    static final int FIXED_WRAP_GUTTER_MIN = 16; //dps
+    static final int MOTION_NON_ADJACENT_OFFSET = 24;
 
     private static final int ANIMATION_DURATION = 300;
 
@@ -239,27 +240,27 @@
 
     private final SlidingTabStrip mTabStrip;
 
-    private int mTabPaddingStart;
-    private int mTabPaddingTop;
-    private int mTabPaddingEnd;
-    private int mTabPaddingBottom;
+    int mTabPaddingStart;
+    int mTabPaddingTop;
+    int mTabPaddingEnd;
+    int mTabPaddingBottom;
 
-    private int mTabTextAppearance;
-    private ColorStateList mTabTextColors;
-    private float mTabTextSize;
-    private float mTabTextMultiLineSize;
+    int mTabTextAppearance;
+    ColorStateList mTabTextColors;
+    float mTabTextSize;
+    float mTabTextMultiLineSize;
 
-    private final int mTabBackgroundResId;
+    final int mTabBackgroundResId;
 
-    private int mTabMaxWidth = Integer.MAX_VALUE;
+    int mTabMaxWidth = Integer.MAX_VALUE;
     private final int mRequestedTabMinWidth;
     private final int mRequestedTabMaxWidth;
     private final int mScrollableTabMinWidth;
 
     private int mContentInsetStart;
 
-    private int mTabGravity;
-    private int mMode;
+    int mTabGravity;
+    int mMode;
 
     private OnTabSelectedListener mSelectedListener;
     private final ArrayList<OnTabSelectedListener> mSelectedListeners = new ArrayList<>();
@@ -267,7 +268,7 @@
 
     private ValueAnimatorCompat mScrollAnimator;
 
-    private ViewPager mViewPager;
+    ViewPager mViewPager;
     private PagerAdapter mPagerAdapter;
     private DataSetObserver mPagerAdapterObserver;
     private TabLayoutOnPageChangeListener mPageChangeListener;
@@ -399,7 +400,7 @@
         setScrollPosition(position, positionOffset, updateSelectedText, true);
     }
 
-    private void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
+    void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
             boolean updateIndicatorPosition) {
         final int roundedPosition = Math.round(position + positionOffset);
         if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {
@@ -874,7 +875,7 @@
                 - getPaddingRight());
     }
 
-    private void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
+    void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
         if (mPagerAdapter != null && mPagerAdapterObserver != null) {
             // If we already have a PagerAdapter, unregister our observer
             mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
@@ -894,7 +895,7 @@
         populateFromPagerAdapter();
     }
 
-    private void populateFromPagerAdapter() {
+    void populateFromPagerAdapter() {
         removeAllTabs();
 
         if (mPagerAdapter != null) {
@@ -990,7 +991,7 @@
         }
     }
 
-    private int dpToPx(int dps) {
+    int dpToPx(int dps) {
         return Math.round(getResources().getDisplayMetrics().density * dps);
     }
 
@@ -1199,7 +1200,7 @@
         updateTabViews(true);
     }
 
-    private void updateTabViews(final boolean requestLayout) {
+    void updateTabViews(final boolean requestLayout) {
         for (int i = 0; i < mTabStrip.getChildCount(); i++) {
             View child = mTabStrip.getChildAt(i);
             child.setMinimumWidth(getTabMinWidth());
@@ -1229,10 +1230,10 @@
         private int mPosition = INVALID_POSITION;
         private View mCustomView;
 
-        private TabLayout mParent;
-        private TabView mView;
+        TabLayout mParent;
+        TabView mView;
 
-        private Tab() {
+        Tab() {
             // Private constructor
         }
 
@@ -1462,13 +1463,13 @@
             return mContentDesc;
         }
 
-        private void updateView() {
+        void updateView() {
             if (mView != null) {
                 mView.update();
             }
         }
 
-        private void reset() {
+        void reset() {
             mParent = null;
             mView = null;
             mTag = null;
@@ -1494,7 +1495,8 @@
         public TabView(Context context) {
             super(context);
             if (mTabBackgroundResId != 0) {
-                setBackgroundDrawable(AppCompatResources.getDrawable(context, mTabBackgroundResId));
+                ViewCompat.setBackground(
+                        this, AppCompatResources.getDrawable(context, mTabBackgroundResId));
             }
             ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
                     mTabPaddingEnd, mTabPaddingBottom);
@@ -1505,13 +1507,16 @@
 
         @Override
         public boolean performClick() {
-            final boolean value = super.performClick();
+            final boolean handled = super.performClick();
 
             if (mTab != null) {
+                if (!handled) {
+                    playSoundEffect(SoundEffectConstants.CLICK);
+                }
                 mTab.select();
                 return true;
             } else {
-                return value;
+                return handled;
             }
         }
 
@@ -1621,14 +1626,14 @@
             }
         }
 
-        private void setTab(@Nullable final Tab tab) {
+        void setTab(@Nullable final Tab tab) {
             if (tab != mTab) {
                 mTab = tab;
                 update();
             }
         }
 
-        private void reset() {
+        void reset() {
             setTab(null);
             setSelected(false);
         }
@@ -1683,7 +1688,7 @@
                     mTextView = textView;
                     mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
                 }
-                mTextView.setTextAppearance(getContext(), mTabTextAppearance);
+                TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);
                 if (mTabTextColors != null) {
                     mTextView.setTextColor(mTabTextColors);
                 }
@@ -1798,8 +1803,8 @@
         private int mSelectedIndicatorHeight;
         private final Paint mSelectedIndicatorPaint;
 
-        private int mSelectedPosition = -1;
-        private float mSelectionOffset;
+        int mSelectedPosition = -1;
+        float mSelectionOffset;
 
         private int mIndicatorLeft = -1;
         private int mIndicatorRight = -1;
@@ -1947,7 +1952,7 @@
             setIndicatorPosition(left, right);
         }
 
-        private void setIndicatorPosition(int left, int right) {
+        void setIndicatorPosition(int left, int right) {
             if (left != mIndicatorLeft || right != mIndicatorRight) {
                 // If the indicator's left/right has changed, invalidate
                 mIndicatorLeft = left;
@@ -2084,7 +2089,7 @@
         return generateDefaultLayoutParams();
     }
 
-    private int getTabMaxWidth() {
+    int getTabMaxWidth() {
         return mTabMaxWidth;
     }
 
@@ -2145,7 +2150,7 @@
             }
         }
 
-        private void reset() {
+        void reset() {
             mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
         }
     }
@@ -2178,6 +2183,9 @@
     }
 
     private class PagerAdapterObserver extends DataSetObserver {
+        PagerAdapterObserver() {
+        }
+
         @Override
         public void onChanged() {
             populateFromPagerAdapter();
@@ -2192,6 +2200,9 @@
     private class AdapterChangeListener implements ViewPager.OnAdapterChangeListener {
         private boolean mAutoRefresh;
 
+        AdapterChangeListener() {
+        }
+
         @Override
         public void onAdapterChanged(@NonNull ViewPager viewPager,
                 @Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter) {
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 44925f7..fefbf99 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -102,7 +102,7 @@
     private static final String LOG_TAG = "TextInputLayout";
 
     private final FrameLayout mInputFrame;
-    private EditText mEditText;
+    EditText mEditText;
 
     private boolean mHintEnabled;
     private CharSequence mHint;
@@ -114,12 +114,12 @@
     private int mIndicatorsAdded;
 
     private boolean mErrorEnabled;
-    private TextView mErrorView;
+    TextView mErrorView;
     private int mErrorTextAppearance;
     private boolean mErrorShown;
     private CharSequence mError;
 
-    private boolean mCounterEnabled;
+    boolean mCounterEnabled;
     private TextView mCounterView;
     private int mCounterMaxLength;
     private int mCounterTextAppearance;
@@ -144,7 +144,7 @@
     // Only used for testing
     private boolean mHintExpanded;
 
-    private final CollapsingTextHelper mCollapsingTextHelper = new CollapsingTextHelper(this);
+    final CollapsingTextHelper mCollapsingTextHelper = new CollapsingTextHelper(this);
 
     private boolean mHintAnimationEnabled;
     private ValueAnimatorCompat mAnimator;
@@ -371,7 +371,7 @@
         }
     }
 
-    private void updateLabelState(boolean animate) {
+    void updateLabelState(boolean animate) {
         final boolean isEnabled = isEnabled();
         final boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
         final boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
@@ -560,7 +560,7 @@
                 mErrorView = new TextView(getContext());
                 boolean useDefaultColor = false;
                 try {
-                    mErrorView.setTextAppearance(getContext(), mErrorTextAppearance);
+                    TextViewCompat.setTextAppearance(mErrorView, mErrorTextAppearance);
 
                     if (Build.VERSION.SDK_INT >= 23
                             && mErrorView.getTextColors().getDefaultColor() == Color.MAGENTA) {
@@ -577,7 +577,7 @@
                 if (useDefaultColor) {
                     // Probably caused by our theme not extending from Theme.Design*. Instead
                     // we manually set something appropriate
-                    mErrorView.setTextAppearance(getContext(),
+                    TextViewCompat.setTextAppearance(mErrorView,
                             android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Caption);
                     mErrorView.setTextColor(ContextCompat.getColor(
                             getContext(), R.color.design_textinput_error_color_light));
@@ -700,11 +700,11 @@
                 mCounterView = new TextView(getContext());
                 mCounterView.setMaxLines(1);
                 try {
-                    mCounterView.setTextAppearance(getContext(), mCounterTextAppearance);
+                    TextViewCompat.setTextAppearance(mCounterView, mCounterTextAppearance);
                 } catch (Exception e) {
                     // Probably caused by our theme not extending from Theme.Design*. Instead
                     // we manually set something appropriate
-                    mCounterView.setTextAppearance(getContext(),
+                    TextViewCompat.setTextAppearance(mCounterView,
                             android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Caption);
                     mCounterView.setTextColor(ContextCompat.getColor(
                             getContext(), R.color.design_textinput_error_color_light));
@@ -782,7 +782,7 @@
         return mCounterMaxLength;
     }
 
-    private void updateCounter(int length) {
+    void updateCounter(int length) {
         boolean wasCounterOverflowed = mCounterOverflowed;
         if (mCounterMaxLength == INVALID_MAX_LENGTH) {
             mCounterView.setText(String.valueOf(length));
@@ -790,7 +790,7 @@
         } else {
             mCounterOverflowed = length > mCounterMaxLength;
             if (wasCounterOverflowed != mCounterOverflowed) {
-                mCounterView.setTextAppearance(getContext(), mCounterOverflowed ?
+                TextViewCompat.setTextAppearance(mCounterView, mCounterOverflowed ?
                         mCounterOverflowTextAppearance : mCounterTextAppearance);
             }
             mCounterView.setText(getContext().getString(R.string.character_counter_pattern,
@@ -867,7 +867,7 @@
                 // as the background. This has the unfortunate side-effect of wiping out any
                 // user set padding, but I'd hope that use of custom padding on an EditText
                 // is limited.
-                mEditText.setBackgroundDrawable(newBg);
+                ViewCompat.setBackground(mErrorView, newBg);
                 mHasReconstructedEditTextBackground = true;
             }
         }
@@ -1193,7 +1193,7 @@
         applyPasswordToggleTint();
     }
 
-   private void passwordVisibilityToggleRequested() {
+   void passwordVisibilityToggleRequested() {
        if (mPasswordToggleEnabled) {
            // Store the current cursor position
            final int selection = mEditText.getSelectionEnd();
@@ -1346,6 +1346,9 @@
     }
 
     private class TextInputAccessibilityDelegate extends AccessibilityDelegateCompat {
+        TextInputAccessibilityDelegate() {
+        }
+
         @Override
         public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
             super.onInitializeAccessibilityEvent(host, event);
diff --git a/design/src/android/support/design/widget/ViewGroupUtils.java b/design/src/android/support/design/widget/ViewGroupUtils.java
index a5d2f8a..bb5e1b6 100644
--- a/design/src/android/support/design/widget/ViewGroupUtils.java
+++ b/design/src/android/support/design/widget/ViewGroupUtils.java
@@ -28,6 +28,9 @@
     }
 
     private static class ViewGroupUtilsImplBase implements ViewGroupUtilsImpl {
+        ViewGroupUtilsImplBase() {
+        }
+
         @Override
         public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
             parent.offsetDescendantRectToMyCoords(child, rect);
@@ -39,6 +42,9 @@
     }
 
     private static class ViewGroupUtilsImplHoneycomb implements ViewGroupUtilsImpl {
+        ViewGroupUtilsImplHoneycomb() {
+        }
+
         @Override
         public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
             ViewGroupUtilsHoneycomb.offsetDescendantRect(parent, child, rect);
diff --git a/design/tests/AndroidManifest.xml b/design/tests/AndroidManifest.xml
index 9582f81..9e859e6 100755
--- a/design/tests/AndroidManifest.xml
+++ b/design/tests/AndroidManifest.xml
@@ -78,6 +78,10 @@
             android:name="android.support.design.widget.NavigationViewActivity"/>
 
         <activity
+            android:theme="@style/Theme.AppCompat.NoActionBar"
+            android:name="android.support.design.widget.BottomNavigationViewActivity"/>
+
+        <activity
               android:theme="@style/Theme.AppCompat.NoActionBar"
               android:name="android.support.design.widget.TextInputLayoutActivity"/>
 
diff --git a/design/tests/res/layout/design_bottom_navigation_view.xml b/design/tests/res/layout/design_bottom_navigation_view.xml
new file mode 100644
index 0000000..0e85aad
--- /dev/null
+++ b/design/tests/res/layout/design_bottom_navigation_view.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <android.support.design.widget.BottomNavigationView
+        android:id="@+id/bottom_navigation"
+        android:layout_height="56dp"
+        android:layout_width="match_parent"
+        app:menu="@menu/bottom_navigation_view_content"
+        app:itemIconTint="@color/emerald_translucent"
+        app:itemTextColor="@color/emerald_text"
+        app:itemBackground="@color/sand_default" />
+</FrameLayout>
\ No newline at end of file
diff --git a/design/tests/res/menu/bottom_navigation_view_content.xml b/design/tests/res/menu/bottom_navigation_view_content.xml
new file mode 100644
index 0000000..6d19060
--- /dev/null
+++ b/design/tests/res/menu/bottom_navigation_view_content.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 Google Inc.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/destination_home"
+          android:title="@string/navigate_home"
+          android:icon="@drawable/test_drawable_red" />
+    <item android:id="@+id/destination_profile"
+          android:title="@string/navigate_profile"
+          android:icon="@drawable/test_drawable_green" />
+    <item android:id="@+id/destination_people"
+          android:title="@string/navigate_people"
+          android:icon="@drawable/test_drawable_blue" />
+</menu>
diff --git a/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java b/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java
new file mode 100644
index 0000000..31b527f
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.testutils;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.IdRes;
+import android.support.annotation.Nullable;
+import android.support.design.widget.BottomNavigationView;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.view.View;
+
+import org.hamcrest.Matcher;
+
+
+public class BottomNavigationViewActions {
+    /**
+     * Sets item icon tint list on the content of the bottom navigation view.
+     */
+    public static ViewAction setItemIconTintList(@Nullable final ColorStateList tint) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return isDisplayed();
+            }
+
+            @Override
+            public String getDescription() {
+                return "Set item icon tint list";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                BottomNavigationView navigationView = (BottomNavigationView) view;
+                navigationView.setItemIconTintList(tint);
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
+    /**
+     * Sets icon for the menu item of the navigation view.
+     */
+    public static ViewAction setIconForMenuItem(@IdRes final int menuItemId,
+            final Drawable iconDrawable) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return isDisplayed();
+            }
+
+            @Override
+            public String getDescription() {
+                return "Set menu item icon";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                BottomNavigationView navigationView = (BottomNavigationView) view;
+                navigationView.getMenu().findItem(menuItemId).setIcon(iconDrawable);
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
index 4199fa9..d04a510 100644
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
@@ -308,6 +308,13 @@
         final ImageView parallaxImageView =
                 (ImageView) mCoordinatorLayout.findViewById(R.id.app_bar_image);
 
+        // We have not set any padding on the ImageView, so ensure that none is set via
+        // window insets handling
+        assertEquals(0, parallaxImageView.getPaddingLeft());
+        assertEquals(0, parallaxImageView.getPaddingTop());
+        assertEquals(0, parallaxImageView.getPaddingRight());
+        assertEquals(0, parallaxImageView.getPaddingBottom());
+
         CollapsingToolbarLayout.LayoutParams parallaxImageViewLp =
                 (CollapsingToolbarLayout.LayoutParams) parallaxImageView.getLayoutParams();
         assertEquals(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PARALLAX,
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
similarity index 63%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
index 3946f1d..2afe695 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,14 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.support.design.widget;
 
-package android.support.v4.app;
+import android.support.design.test.R;
 
-import android.app.Activity;
-import android.net.Uri;
-
-class ActivityCompat22 {
-    public static Uri getReferrer(Activity activity) {
-        return activity.getReferrer();
+public class BottomNavigationViewActivity extends BaseTestActivity {
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.design_bottom_navigation_view;
     }
 }
diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
new file mode 100644
index 0000000..98851b4
--- /dev/null
+++ b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.design.widget;
+
+import static android.support.design.testutils.BottomNavigationViewActions.setIconForMenuItem;
+import static android.support.design.testutils.BottomNavigationViewActions.setItemIconTintList;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.hamcrest.core.AllOf.allOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.res.Resources;
+import android.support.annotation.ColorInt;
+import android.support.design.test.R;
+import android.support.design.testutils.TestDrawable;
+import android.support.design.testutils.TestUtilsMatchers;
+import android.support.v4.content.res.ResourcesCompat;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BottomNavigationViewTest
+        extends BaseInstrumentationTestCase<BottomNavigationViewActivity> {
+    private static final int[] MENU_CONTENT_ITEM_IDS = { R.id.destination_home,
+            R.id.destination_profile, R.id.destination_people };
+    private Map<Integer, String> mMenuStringContent;
+
+    private BottomNavigationView mBottomNavigation;
+
+    public BottomNavigationViewTest() {
+        super(BottomNavigationViewActivity.class);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        final BottomNavigationViewActivity activity = mActivityTestRule.getActivity();
+        mBottomNavigation = (BottomNavigationView) activity.findViewById(R.id.bottom_navigation);
+
+        final Resources res = activity.getResources();
+        mMenuStringContent = new HashMap<>(MENU_CONTENT_ITEM_IDS.length);
+        mMenuStringContent.put(R.id.destination_home, res.getString(R.string.navigate_home));
+        mMenuStringContent.put(R.id.destination_profile, res.getString(R.string.navigate_profile));
+        mMenuStringContent.put(R.id.destination_people, res.getString(R.string.navigate_people));
+    }
+
+    @Test
+    @SmallTest
+    public void testBasics() {
+        // Check the contents of the Menu object
+        final Menu menu = mBottomNavigation.getMenu();
+        assertNotNull("Menu should not be null", menu);
+        assertEquals("Should have matching number of items", MENU_CONTENT_ITEM_IDS.length,
+                menu.size());
+        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+            final MenuItem currItem = menu.getItem(i);
+            assertEquals("ID for Item #" + i, MENU_CONTENT_ITEM_IDS[i], currItem.getItemId());
+        }
+
+    }
+
+    @Test
+    @SmallTest
+    public void testNavigationSelectionListener() {
+        BottomNavigationView.OnNavigationItemSelectedListener mockedListener =
+                mock(BottomNavigationView.OnNavigationItemSelectedListener.class);
+        mBottomNavigation.setOnNavigationItemSelectedListener(mockedListener);
+
+        // Click one of our items
+        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
+                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
+        // And that our listener has been notified of the click
+        verify(mockedListener, times(1)).onNavigationItemSelected(
+                mBottomNavigation.getMenu().findItem(R.id.destination_profile));
+
+        // Set null listener to test that the next click is not going to notify the
+        // previously set listener
+        mBottomNavigation.setOnNavigationItemSelectedListener(null);
+
+        // Click one of our items
+        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
+                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
+        // And that our previous listener has not been notified of the click
+        verifyNoMoreInteractions(mockedListener);
+    }
+
+    @Test
+    @SmallTest
+    public void testIconTinting() {
+        final Resources res = mActivityTestRule.getActivity().getResources();
+        @ColorInt final int redFill = ResourcesCompat.getColor(res, R.color.test_red, null);
+        @ColorInt final int greenFill = ResourcesCompat.getColor(res, R.color.test_green, null);
+        @ColorInt final int blueFill = ResourcesCompat.getColor(res, R.color.test_blue, null);
+        final int iconSize = res.getDimensionPixelSize(R.dimen.drawable_small_size);
+        onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_home,
+                new TestDrawable(redFill, iconSize, iconSize)));
+        onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_profile,
+                new TestDrawable(greenFill, iconSize, iconSize)));
+        onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_people,
+                new TestDrawable(blueFill, iconSize, iconSize)));
+
+        @ColorInt final int defaultTintColor = ResourcesCompat.getColor(res,
+                R.color.emerald_translucent, null);
+
+        // We're allowing a margin of error in checking the color of the items' icons.
+        // This is due to the translucent color being used in the icon tinting
+        // and off-by-one discrepancies of SRC_IN when it's compositing
+        // translucent color. Note that all the checks below are written for the current
+        // logic on BottomNavigationView that uses the default SRC_IN tint mode - effectively
+        // replacing all non-transparent pixels in the destination (original icon) with
+        // our translucent tint color.
+        final int allowedComponentVariance = 1;
+
+        // Note that here we're tying ourselves to the implementation details of the internal
+        // structure of the BottomNavigationView. Specifically, we're checking the drawable the
+        // ImageView with id R.id.icon. If the internal implementation of BottomNavigationView
+        // changes, the second Matcher in the lookups below will need to be tweaked.
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
+                matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
+                matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
+                matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
+
+        @ColorInt final int newTintColor = ResourcesCompat.getColor(res,
+                R.color.red_translucent, null);
+        onView(withId(R.id.bottom_navigation)).perform(setItemIconTintList(
+                ResourcesCompat.getColorStateList(res, R.color.color_state_list_red_translucent,
+                        null)));
+        // Check that all menu items with icons now have icons tinted with the newly set color
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
+                matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
+                matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
+                matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
+
+        // And now remove all icon tinting
+        onView(withId(R.id.bottom_navigation)).perform(setItemIconTintList(null));
+        // And verify that all menu items with icons now have the original colors for their icons.
+        // Note that since there is no tinting at this point, we don't allow any color variance
+        // in these checks.
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
+                matches(TestUtilsMatchers.drawable(redFill, allowedComponentVariance)));
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
+                matches(TestUtilsMatchers.drawable(greenFill, allowedComponentVariance)));
+        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
+                matches(TestUtilsMatchers.drawable(blueFill, allowedComponentVariance)));
+    }
+}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
index 050739b..7cfce3d 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
@@ -24,11 +24,13 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BottomSheetBehaviorInitialStateTest {
 
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
index 4c03fd6..cb91cec 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
@@ -55,6 +55,7 @@
 import android.widget.TextView;
 
 import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
 import org.junit.Test;
 
 public class BottomSheetBehaviorTest extends
@@ -183,7 +184,7 @@
 
         @Override
         public Matcher<View> getConstraints() {
-            return ViewMatchers.isDisplayed();
+            return Matchers.any(View.class);
         }
 
         @Override
@@ -213,7 +214,6 @@
                         MotionEvents.sendCancel(uiController, downEvent);
                         throw new RuntimeException("Cannot drag: failed to send a move event.");
                     }
-                    BottomSheetBehavior behavior = BottomSheetBehavior.from(view);
                 }
                 int duration = ViewConfiguration.getPressedStateDuration();
                 if (duration > 0) {
@@ -460,6 +460,46 @@
 
     @Test
     @MediumTest
+    public void testInvisibleThenVisible() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                // The bottom sheet is initially invisible
+                getBottomSheet().setVisibility(View.INVISIBLE);
+                // Then it becomes visible when the CoL is touched
+                getCoordinatorLayout().setOnTouchListener(new View.OnTouchListener() {
+                    @Override
+                    public boolean onTouch(View view, MotionEvent e) {
+                        if (e.getAction() == MotionEvent.ACTION_DOWN) {
+                            getBottomSheet().setVisibility(View.VISIBLE);
+                            return true;
+                        }
+                        return false;
+                    }
+                });
+                assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
+            }
+        });
+        // Drag over the CoL
+        Espresso.onView(ViewMatchers.withId(R.id.coordinator))
+                // Drag (and not release)
+                .perform(new DragAction(
+                        GeneralLocation.BOTTOM_CENTER,
+                        GeneralLocation.TOP_CENTER,
+                        Press.FINGER))
+                .check(new ViewAssertion() {
+                    @Override
+                    public void check(View view, NoMatchingViewException e) {
+                        // The bottom sheet should not react to the touch events
+                        assertThat(getBottomSheet(), is(ViewMatchers.isDisplayed()));
+                        assertThat(getBehavior().getState(),
+                                is(BottomSheetBehavior.STATE_COLLAPSED));
+                    }
+                });
+    }
+
+    @Test
+    @MediumTest
     public void testNestedScroll() {
         final ViewGroup bottomSheet = getBottomSheet();
         final BottomSheetBehavior behavior = getBehavior();
@@ -491,7 +531,7 @@
         // Swipe from the very bottom of the bottom sheet to the top edge of the screen so that the
         // scrolling content is also scrolled
         Espresso.onView(ViewMatchers.withId(R.id.coordinator))
-                .perform(new GeneralSwipeAction(Swipe.FAST,
+                .perform(new GeneralSwipeAction(Swipe.SLOW,
                         new CoordinatesProvider() {
                             @Override
                             public float[] calculateCoordinates(View view) {
@@ -618,8 +658,10 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
+                CoordinatorLayout col = getCoordinatorLayout();
                 assertThat(getBottomSheet().getTop(),
-                        is(getCoordinatorLayout().getWidth() * 9 / 16));
+                        is(Math.min(col.getWidth() * 9 / 16,
+                                col.getHeight() - getBehavior().getPeekHeightMin())));
             }
         });
     }
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
index ea5872e..fe62e441 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
@@ -28,6 +28,7 @@
 import android.support.test.espresso.ViewAssertion;
 import android.support.test.espresso.action.ViewActions;
 import android.support.v4.view.MotionEventCompat;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -35,6 +36,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
+@MediumTest
 public class BottomSheetBehaviorTouchTest extends
         BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
 
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
index 5471c38..f6350c1 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
@@ -293,4 +293,45 @@
         // And assert that View B's Behavior was called appropriately
         verify(behavior, times(1)).onDependentViewRemoved(col, viewB, viewA);
     }
+
+    @Test
+    public void testGetDependenciesAfterDependentViewRemoved() {
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        // Add two views, A & B, where B depends on A
+        final View viewA = new View(col.getContext());
+        final View viewB = new View(col.getContext());
+        final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
+        final CoordinatorLayout.Behavior behavior
+                = new CoordinatorLayoutUtils.DependentBehavior(viewA) {
+            @Override
+            public void onDependentViewRemoved(CoordinatorLayout parent, View child,
+                    View dependency) {
+                parent.getDependencies(child);
+            }
+        };
+        lpB.setBehavior(behavior);
+
+        // Now add views
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(viewA);
+                col.addView(viewB, lpB);
+            }
+        });
+
+        // Wait for a layout
+        instrumentation.waitForIdleSync();
+
+        // Now remove view A, which will trigger onDependentViewRemoved() on view B's behavior
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                col.removeView(viewA);
+            }
+        });
+    }
+
 }
diff --git a/fragment/java/android/support/v4/app/BackStackRecord.java b/fragment/java/android/support/v4/app/BackStackRecord.java
index 042cf9d..2b8cd13 100644
--- a/fragment/java/android/support/v4/app/BackStackRecord.java
+++ b/fragment/java/android/support/v4/app/BackStackRecord.java
@@ -348,7 +348,7 @@
                                 writer.println("Removed:");
                             }
                             writer.print(innerPrefix); writer.print("  #"); writer.print(i);
-                                    writer.print(": "); 
+                                    writer.print(": ");
                         }
                         writer.println(op.removed.get(i));
                     }
@@ -678,7 +678,7 @@
         disallowAddToBackStack();
         mManager.execSingleAction(this, true);
     }
-    
+
     int commitInternal(boolean allowStateLoss) {
         if (mCommitted) throw new IllegalStateException("commit already called");
         if (FragmentManagerImpl.DEBUG) {
@@ -1349,7 +1349,7 @@
         }
     }
 
-    private void callSharedElementEnd(TransitionState state, Fragment inFragment,
+    void callSharedElementEnd(TransitionState state, Fragment inFragment,
             Fragment outFragment, boolean isBack, ArrayMap<String, View> namedViews) {
         SharedElementCallback sharedElementCallback = isBack ?
                 outFragment.mEnterTransitionCallback :
@@ -1361,7 +1361,7 @@
         }
     }
 
-    private void setEpicenterIn(ArrayMap<String, View> namedViews, TransitionState state) {
+    void setEpicenterIn(ArrayMap<String, View> namedViews, TransitionState state) {
         if (mSharedElementTargetNames != null && !namedViews.isEmpty()) {
             // now we know the epicenter of the entering transition.
             View epicenter = namedViews
@@ -1372,7 +1372,7 @@
         }
     }
 
-    private ArrayMap<String, View> mapSharedElementsIn(TransitionState state,
+    ArrayMap<String, View> mapSharedElementsIn(TransitionState state,
             boolean isBack, Fragment inFragment) {
         // Now map the shared elements in the incoming fragment
         ArrayMap<String, View> namedViews = mapEnteringSharedElements(state, inFragment, isBack);
@@ -1459,7 +1459,7 @@
         });
     }
 
-    private void excludeHiddenFragments(TransitionState state, int containerId, Object transition) {
+    void excludeHiddenFragments(TransitionState state, int containerId, Object transition) {
         if (mManager.mAdded != null) {
             for (int i = 0; i < mManager.mAdded.size(); i++) {
                 Fragment fragment = mManager.mAdded.get(i);
diff --git a/fragment/java/android/support/v4/app/FragmentActivity.java b/fragment/java/android/support/v4/app/FragmentActivity.java
index c4953c0..18ee2ae 100644
--- a/fragment/java/android/support/v4/app/FragmentActivity.java
+++ b/fragment/java/android/support/v4/app/FragmentActivity.java
@@ -34,7 +34,6 @@
 import android.support.v4.util.SparseArrayCompat;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -200,7 +199,7 @@
     final public void setSupportMediaController(MediaControllerCompat mediaController) {
         mMediaController = mediaController;
         if (android.os.Build.VERSION.SDK_INT >= 21) {
-            ActivityCompat21.setMediaController(this, mediaController.getMediaController());
+            ActivityCompatApi21.setMediaController(this, mediaController.getMediaController());
         }
     }
 
@@ -406,11 +405,11 @@
         if (super.onMenuItemSelected(featureId, item)) {
             return true;
         }
-        
+
         switch (featureId) {
             case Window.FEATURE_OPTIONS_PANEL:
                 return mFragments.dispatchOptionsItemSelected(item);
-                
+
             case Window.FEATURE_CONTEXT_MENU:
                 return mFragments.dispatchContextItemSelected(item);
 
@@ -431,7 +430,7 @@
         }
         super.onPanelClosed(featureId, menu);
     }
-    
+
     /**
      * Dispatch onPause() to fragments.
      */
@@ -985,7 +984,7 @@
     /**
      * Called by Fragment.requestPermissions() to implement its behavior.
      */
-    private void requestPermissionsFromFragment(Fragment fragment, String[] permissions,
+    void requestPermissionsFromFragment(Fragment fragment, String[] permissions,
             int requestCode) {
         if (requestCode == -1) {
             ActivityCompat.requestPermissions(this, permissions, requestCode);
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 6f251e7..481a9bd 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -76,7 +76,7 @@
      * with {@link FragmentTransaction#addToBackStack(String)
      * FragmentTransaction.addToBackStack()}.  Entries can later be
      * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
-     * FragmentManager.getBackStackEntry()}.
+     * FragmentManager.getBackStackEntryAt()}.
      *
      * <p>Note that you should never hold on to a BackStackEntry object;
      * the identifier as returned by {@link #getId} is the only thing that
@@ -137,7 +137,7 @@
     /**
      * Start a series of edit operations on the Fragments associated with
      * this FragmentManager.
-     * 
+     *
      * <p>Note: A fragment transaction can only be created/committed prior
      * to an activity saving its state.  If you try to commit a transaction
      * after {@link FragmentActivity#onSaveInstanceState FragmentActivity.onSaveInstanceState()}
@@ -157,7 +157,7 @@
     public FragmentTransaction openTransaction() {
         return beginTransaction();
     }
-    
+
     /**
      * After a {@link FragmentTransaction} is committed with
      * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
@@ -230,7 +230,7 @@
      * This function is asynchronous -- it enqueues the
      * request to pop, but the action will not be performed until the application
      * returns to its event loop.
-     * 
+     *
      * @param name If non-null, this is the name of a previous back state
      * to look for; if found, all states up to that state will be popped.  The
      * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
@@ -252,7 +252,7 @@
      * This function is asynchronous -- it enqueues the
      * request to pop, but the action will not be performed until the application
      * returns to its event loop.
-     * 
+     *
      * @param id Identifier of the stated to be popped. If no identifier exists,
      * false is returned.
      * The identifier is the number returned by
@@ -378,10 +378,10 @@
     FragmentState[] mActive;
     int[] mAdded;
     BackStackState[] mBackStack;
-    
+
     public FragmentManagerState() {
     }
-    
+
     public FragmentManagerState(Parcel in) {
         mActive = in.createTypedArray(FragmentState.CREATOR);
         mAdded = in.createIntArray();
@@ -399,7 +399,7 @@
         dest.writeIntArray(mAdded);
         dest.writeTypedArray(mBackStack, flags);
     }
-    
+
     public static final Parcelable.Creator<FragmentManagerState> CREATOR
             = new Parcelable.Creator<FragmentManagerState>() {
         @Override
@@ -420,7 +420,7 @@
 final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
     static boolean DEBUG = false;
     static final String TAG = "FragmentManager";
-    
+
     static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11;
 
     static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
@@ -431,7 +431,7 @@
     static class AnimateOnHWLayerIfNeededListener implements AnimationListener {
         private AnimationListener mOriginalListener;
         private boolean mShouldRunOnHWLayer;
-        private View mView;
+        View mView;
 
         public AnimateOnHWLayerIfNeededListener(final View v, Animation anim) {
             if (v == null || anim == null) {
@@ -499,13 +499,13 @@
     ArrayList<Runnable> mPendingActions;
     Runnable[] mTmpActions;
     boolean mExecutingActions;
-    
+
     ArrayList<Fragment> mActive;
     ArrayList<Fragment> mAdded;
     ArrayList<Integer> mAvailIndices;
     ArrayList<BackStackRecord> mBackStack;
     ArrayList<Fragment> mCreatedMenus;
-    
+
     // Must be accessed while locked.
     ArrayList<BackStackRecord> mBackStackIndices;
     ArrayList<Integer> mAvailBackStackIndices;
@@ -519,17 +519,17 @@
     Fragment mParent;
 
     static Field sAnimationListenerField = null;
-    
+
     boolean mNeedMenuInvalidate;
     boolean mStateSaved;
     boolean mDestroyed;
     String mNoTransactionsBecause;
     boolean mHavePendingDeferredStart;
-    
+
     // Temporary vars for state save and restore.
     Bundle mStateBundle = null;
     SparseArray<Parcelable> mStateArray = null;
-    
+
     Runnable mExecCommit = new Runnable() {
         @Override
         public void run() {
@@ -850,9 +850,9 @@
     static final Interpolator DECELERATE_CUBIC = new DecelerateInterpolator(1.5f);
     static final Interpolator ACCELERATE_QUINT = new AccelerateInterpolator(2.5f);
     static final Interpolator ACCELERATE_CUBIC = new AccelerateInterpolator(1.5f);
-    
+
     static final int ANIM_DUR = 220;
-    
+
     static Animation makeOpenCloseAnimation(Context context, float startScale,
             float endScale, float startAlpha, float endAlpha) {
         AnimationSet set = new AnimationSet(false);
@@ -867,7 +867,7 @@
         set.addAnimation(alpha);
         return set;
     }
-    
+
     static Animation makeFadeAnimation(Context context, float start, float end) {
         AlphaAnimation anim = new AlphaAnimation(start, end);
         anim.setInterpolator(DECELERATE_CUBIC);
@@ -882,18 +882,18 @@
         if (animObj != null) {
             return animObj;
         }
-        
+
         if (fragment.mNextAnim != 0) {
             Animation anim = AnimationUtils.loadAnimation(mHost.getContext(), fragment.mNextAnim);
             if (anim != null) {
                 return anim;
             }
         }
-        
+
         if (transit == 0) {
             return null;
         }
-        
+
         int styleIndex = transitToStyleIndex(transit, enter);
         if (styleIndex < 0) {
             return null;
@@ -913,27 +913,27 @@
             case ANIM_STYLE_FADE_EXIT:
                 return makeFadeAnimation(mHost.getContext(), 1, 0);
         }
-        
+
         if (transitionStyle == 0 && mHost.onHasWindowAnimations()) {
             transitionStyle = mHost.onGetWindowAnimations();
         }
         if (transitionStyle == 0) {
             return null;
         }
-        
+
         //TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
         //        com.android.internal.R.styleable.FragmentAnimation);
         //int anim = attrs.getResourceId(styleIndex, 0);
         //attrs.recycle();
-        
+
         //if (anim == 0) {
         //    return null;
         //}
-        
+
         //return AnimatorInflater.loadAnimator(mActivity, anim);
         return null;
     }
-    
+
     public void performPendingDeferredStart(Fragment f) {
         if (f.mDeferStart) {
             if (mExecutingActions) {
@@ -1004,7 +1004,7 @@
             // being reloaded from the layout.
             if (f.mFromLayout && !f.mInLayout) {
                 return;
-            }  
+            }
             if (f.mAnimatingAway != null) {
                 // The fragment is currently being animated...  but!  Now we
                 // want to move our state back up.  Give up on waiting for the
@@ -1263,7 +1263,7 @@
             f.mState = newState;
         }
     }
-    
+
     void moveToState(Fragment f) {
         moveToState(f, mCurState, 0, 0, false);
     }
@@ -1271,7 +1271,7 @@
     void moveToState(int newState, boolean always) {
         moveToState(newState, 0, 0, always);
     }
-    
+
     void moveToState(int newState, int transit, int transitStyle, boolean always) {
         if (mHost == null && newState != Fragment.INITIALIZING) {
             throw new IllegalStateException("No host");
@@ -1315,31 +1315,31 @@
             }
         }
     }
-    
+
     void makeActive(Fragment f) {
         if (f.mIndex >= 0) {
             return;
         }
-        
+
         if (mAvailIndices == null || mAvailIndices.size() <= 0) {
             if (mActive == null) {
                 mActive = new ArrayList<Fragment>();
             }
             f.setIndex(mActive.size(), mParent);
             mActive.add(f);
-            
+
         } else {
             f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
             mActive.set(f.mIndex, f);
         }
         if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
     }
-    
+
     void makeInactive(Fragment f) {
         if (f.mIndex < 0) {
             return;
         }
-        
+
         if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
         mActive.set(f.mIndex, null);
         if (mAvailIndices == null) {
@@ -1349,7 +1349,7 @@
         mHost.inactivateFragment(f.mWho);
         f.initState();
     }
-    
+
     public void addFragment(Fragment fragment, boolean moveToStateNow) {
         if (mAdded == null) {
             mAdded = new ArrayList<Fragment>();
@@ -1371,7 +1371,7 @@
             }
         }
     }
-    
+
     public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
         if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
         final boolean inactive = !fragment.isInBackStack();
@@ -1388,7 +1388,7 @@
                     transition, transitionStyle, false);
         }
     }
-    
+
     public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
         if (DEBUG) Log.v(TAG, "hide: " + fragment);
         if (!fragment.mHidden) {
@@ -1408,7 +1408,7 @@
             fragment.onHiddenChanged(true);
         }
     }
-    
+
     public void showFragment(Fragment fragment, int transition, int transitionStyle) {
         if (DEBUG) Log.v(TAG, "show: " + fragment);
         if (fragment.mHidden) {
@@ -1428,7 +1428,7 @@
             fragment.onHiddenChanged(false);
         }
     }
-    
+
     public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
         if (DEBUG) Log.v(TAG, "detach: " + fragment);
         if (!fragment.mDetached) {
@@ -1515,7 +1515,7 @@
         }
         return null;
     }
-    
+
     public Fragment findFragmentByWho(String who) {
         if (mActive != null && who != null) {
             for (int i=mActive.size()-1; i>=0; i--) {
@@ -1527,7 +1527,7 @@
         }
         return null;
     }
-    
+
     private void checkStateLoss() {
         if (mStateSaved) {
             throw new IllegalStateException(
@@ -1564,7 +1564,7 @@
             }
         }
     }
-    
+
     public int allocBackStackIndex(BackStackRecord bse) {
         synchronized (this) {
             if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
@@ -1648,7 +1648,7 @@
         if (mExecutingActions) {
             throw new IllegalStateException("FragmentManager is already executing transactions");
         }
-        
+
         if (Looper.myLooper() != mHost.getHandler().getLooper()) {
             throw new IllegalStateException("Must be called from main thread of fragment host");
         }
@@ -1657,12 +1657,12 @@
 
         while (true) {
             int numActions;
-            
+
             synchronized (this) {
                 if (mPendingActions == null || mPendingActions.size() == 0) {
                     break;
                 }
-                
+
                 numActions = mPendingActions.size();
                 if (mTmpActions == null || mTmpActions.length < numActions) {
                     mTmpActions = new Runnable[numActions];
@@ -1671,7 +1671,7 @@
                 mPendingActions.clear();
                 mHost.getHandler().removeCallbacks(mExecCommit);
             }
-            
+
             mExecutingActions = true;
             for (int i=0; i<numActions; i++) {
                 mTmpActions[i].run();
@@ -1680,7 +1680,7 @@
             mExecutingActions = false;
             didSomething = true;
         }
-        
+
         doPendingDeferredStart();
 
         return didSomething;
@@ -1717,7 +1717,7 @@
         mBackStack.add(state);
         reportBackStackChanged();
     }
-    
+
     @SuppressWarnings("unused")
     boolean popBackStackState(Handler handler, String name, int id, int flags) {
         if (mBackStack == null) {
@@ -1795,7 +1795,7 @@
         }
         return true;
     }
-    
+
     FragmentManagerNonConfig retainNonConfig() {
         ArrayList<Fragment> fragments = null;
         ArrayList<FragmentManagerNonConfig> childFragments = null;
@@ -1837,7 +1837,7 @@
         }
         return new FragmentManagerNonConfig(fragments, childFragments);
     }
-    
+
     void saveFragmentViewState(Fragment f) {
         if (f.mInnerView == null) {
             return;
@@ -1853,7 +1853,7 @@
             mStateArray = null;
         }
     }
-    
+
     Bundle saveFragmentBasicState(Fragment f) {
         Bundle result = null;
 
@@ -1908,7 +1908,7 @@
         if (mActive == null || mActive.size() <= 0) {
             return null;
         }
-        
+
         // First collect all active fragments.
         int N = mActive.size();
         FragmentState[] active = new FragmentState[N];
@@ -1923,10 +1923,10 @@
                 }
 
                 haveFragments = true;
-                
+
                 FragmentState fs = new FragmentState(f);
                 active[i] = fs;
-                
+
                 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
                     fs.mSavedFragmentState = saveFragmentBasicState(f);
 
@@ -1951,20 +1951,20 @@
                 } else {
                     fs.mSavedFragmentState = f.mSavedFragmentState;
                 }
-                
+
                 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
                         + fs.mSavedFragmentState);
             }
         }
-        
+
         if (!haveFragments) {
             if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
             return null;
         }
-        
+
         int[] added = null;
         BackStackState[] backStack = null;
-        
+
         // Build list of currently added fragments.
         if (mAdded != null) {
             N = mAdded.size();
@@ -1982,7 +1982,7 @@
                 }
             }
         }
-        
+
         // Now save back stack.
         if (mBackStack != null) {
             N = mBackStack.size();
@@ -1995,14 +1995,14 @@
                 }
             }
         }
-        
+
         FragmentManagerState fms = new FragmentManagerState();
         fms.mActive = active;
         fms.mAdded = added;
         fms.mBackStack = backStack;
         return fms;
     }
-    
+
     void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
         // If there is no saved state at all, then there can not be
         // any nonConfig fragments either, so that is that.
@@ -2036,7 +2036,7 @@
                 }
             }
         }
-        
+
         // Build the full list of active fragments, instantiating them from
         // their saved state.
         mActive = new ArrayList<>(fms.mActive.length);
@@ -2066,7 +2066,7 @@
                 mAvailIndices.add(i);
             }
         }
-        
+
         // Update the target of all retained fragments.
         if (nonConfig != null) {
             List<Fragment> nonConfigFragments = nonConfig.getFragments();
@@ -2104,7 +2104,7 @@
         } else {
             mAdded = null;
         }
-        
+
         // Build the back stack.
         if (fms.mBackStack != null) {
             mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
@@ -2134,35 +2134,35 @@
         mContainer = container;
         mParent = parent;
     }
-    
+
     public void noteStateNotSaved() {
         mStateSaved = false;
     }
-    
+
     public void dispatchCreate() {
         mStateSaved = false;
         moveToState(Fragment.CREATED, false);
     }
-    
+
     public void dispatchActivityCreated() {
         mStateSaved = false;
         moveToState(Fragment.ACTIVITY_CREATED, false);
     }
-    
+
     public void dispatchStart() {
         mStateSaved = false;
         moveToState(Fragment.STARTED, false);
     }
-    
+
     public void dispatchResume() {
         mStateSaved = false;
         moveToState(Fragment.RESUMED, false);
     }
-    
+
     public void dispatchPause() {
         moveToState(Fragment.STARTED, false);
     }
-    
+
     public void dispatchStop() {
         // See saveAllState() for the explanation of this.  We do this for
         // all platform versions, to keep our behavior more consistent between
@@ -2171,7 +2171,7 @@
 
         moveToState(Fragment.STOPPED, false);
     }
-    
+
     public void dispatchReallyStop() {
         moveToState(Fragment.ACTIVITY_CREATED, false);
     }
@@ -2266,7 +2266,7 @@
 
         return show;
     }
-    
+
     public boolean dispatchPrepareOptionsMenu(Menu menu) {
         boolean show = false;
         if (mAdded != null) {
@@ -2281,7 +2281,7 @@
         }
         return show;
     }
-    
+
     public boolean dispatchOptionsItemSelected(MenuItem item) {
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
@@ -2295,7 +2295,7 @@
         }
         return false;
     }
-    
+
     public boolean dispatchContextItemSelected(MenuItem item) {
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
@@ -2309,7 +2309,7 @@
         }
         return false;
     }
-    
+
     public void dispatchOptionsMenuClosed(Menu menu) {
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
@@ -2335,16 +2335,16 @@
                 break;
         }
         return rev;
-        
+
     }
-    
+
     public static final int ANIM_STYLE_OPEN_ENTER = 1;
     public static final int ANIM_STYLE_OPEN_EXIT = 2;
     public static final int ANIM_STYLE_CLOSE_ENTER = 3;
     public static final int ANIM_STYLE_CLOSE_EXIT = 4;
     public static final int ANIM_STYLE_FADE_ENTER = 5;
     public static final int ANIM_STYLE_FADE_EXIT = 6;
-    
+
     public static int transitToStyleIndex(int transit, boolean enter) {
         int animAttr = -1;
         switch (transit) {
diff --git a/fragment/java/android/support/v4/app/FragmentTabHost.java b/fragment/java/android/support/v4/app/FragmentTabHost.java
index 2faf5e9..09b89b7 100644
--- a/fragment/java/android/support/v4/app/FragmentTabHost.java
+++ b/fragment/java/android/support/v4/app/FragmentTabHost.java
@@ -21,6 +21,8 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -49,7 +51,8 @@
  */
 public class FragmentTabHost extends TabHost
         implements TabHost.OnTabChangeListener {
-    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+    private final ArrayList<TabInfo> mTabs = new ArrayList<>();
+
     private FrameLayout mRealTabContent;
     private Context mContext;
     private FragmentManager mFragmentManager;
@@ -59,12 +62,12 @@
     private boolean mAttached;
 
     static final class TabInfo {
-        private final String tag;
-        private final Class<?> clss;
-        private final Bundle args;
-        private Fragment fragment;
+        final @NonNull String tag;
+        final @NonNull Class<?> clss;
+        final @Nullable Bundle args;
+        Fragment fragment;
 
-        TabInfo(String _tag, Class<?> _class, Bundle _args) {
+        TabInfo(@NonNull String _tag, @NonNull Class<?> _class, @Nullable Bundle _args) {
             tag = _tag;
             clss = _class;
             args = _args;
@@ -94,7 +97,7 @@
             super(superState);
         }
 
-        private SavedState(Parcel in) {
+        SavedState(Parcel in) {
             super(in);
             curTab = in.readString();
         }
@@ -139,7 +142,7 @@
     }
 
     private void initFragmentTabHost(Context context, AttributeSet attrs) {
-        TypedArray a = context.obtainStyledAttributes(attrs,
+        final TypedArray a = context.obtainStyledAttributes(attrs,
                 new int[] { android.R.attr.inflatedId }, 0, 0);
         mContainerId = a.getResourceId(0, 0);
         a.recycle();
@@ -225,11 +228,12 @@
         mOnTabChangeListener = l;
     }
 
-    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
+    public void addTab(@NonNull TabHost.TabSpec tabSpec, @NonNull Class<?> clss,
+            @Nullable Bundle args) {
         tabSpec.setContent(new DummyTabFactory(mContext));
-        String tag = tabSpec.getTag();
 
-        TabInfo info = new TabInfo(tag, clss, args);
+        final String tag = tabSpec.getTag();
+        final TabInfo info = new TabInfo(tag, clss, args);
 
         if (mAttached) {
             // If we are already attached to the window, then check to make
@@ -237,7 +241,7 @@
             // normally happen.
             info.fragment = mFragmentManager.findFragmentByTag(tag);
             if (info.fragment != null && !info.fragment.isDetached()) {
-                FragmentTransaction ft = mFragmentManager.beginTransaction();
+                final FragmentTransaction ft = mFragmentManager.beginTransaction();
                 ft.detach(info.fragment);
                 ft.commit();
             }
@@ -251,16 +255,16 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
-        String currentTab = getCurrentTabTag();
+        final String currentTag = getCurrentTabTag();
 
         // Go through all tabs and make sure their fragments match
         // the correct state.
         FragmentTransaction ft = null;
-        for (int i=0; i<mTabs.size(); i++) {
-            TabInfo tab = mTabs.get(i);
+        for (int i = 0, count = mTabs.size(); i < count; i++) {
+            final TabInfo tab = mTabs.get(i);
             tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);
             if (tab.fragment != null && !tab.fragment.isDetached()) {
-                if (tab.tag.equals(currentTab)) {
+                if (tab.tag.equals(currentTag)) {
                     // The fragment for this tab is already there and
                     // active, and it is what we really want to have
                     // as the current tab.  Nothing to do.
@@ -279,7 +283,7 @@
         // We are now ready to go.  Make sure we are switched to the
         // correct tab.
         mAttached = true;
-        ft = doTabChanged(currentTab, ft);
+        ft = doTabChanged(currentTag, ft);
         if (ft != null) {
             ft.commit();
             mFragmentManager.executePendingTransactions();
@@ -314,7 +318,7 @@
     @Override
     public void onTabChanged(String tabId) {
         if (mAttached) {
-            FragmentTransaction ft = doTabChanged(tabId, null);
+            final FragmentTransaction ft = doTabChanged(tabId, null);
             if (ft != null) {
                 ft.commit();
             }
@@ -324,26 +328,21 @@
         }
     }
 
-    private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
-        TabInfo newTab = null;
-        for (int i=0; i<mTabs.size(); i++) {
-            TabInfo tab = mTabs.get(i);
-            if (tab.tag.equals(tabId)) {
-                newTab = tab;
-            }
-        }
-        if (newTab == null) {
-            throw new IllegalStateException("No tab known for tag " + tabId);
-        }
+    @Nullable
+    private FragmentTransaction doTabChanged(@Nullable String tag,
+            @Nullable FragmentTransaction ft) {
+        final TabInfo newTab = getTabInfoForTag(tag);
         if (mLastTab != newTab) {
             if (ft == null) {
                 ft = mFragmentManager.beginTransaction();
             }
+
             if (mLastTab != null) {
                 if (mLastTab.fragment != null) {
                     ft.detach(mLastTab.fragment);
                 }
             }
+
             if (newTab != null) {
                 if (newTab.fragment == null) {
                     newTab.fragment = Fragment.instantiate(mContext,
@@ -356,6 +355,18 @@
 
             mLastTab = newTab;
         }
+
         return ft;
     }
+
+    @Nullable
+    private TabInfo getTabInfoForTag(String tabId) {
+        for (int i = 0, count = mTabs.size(); i < count; i++) {
+            final TabInfo tab = mTabs.get(i);
+            if (tab.tag.equals(tabId)) {
+                return tab;
+            }
+        }
+        return null;
+    }
 }
diff --git a/fragment/java/android/support/v4/app/LoaderManager.java b/fragment/java/android/support/v4/app/LoaderManager.java
index 634a6bc..8d777a1 100644
--- a/fragment/java/android/support/v4/app/LoaderManager.java
+++ b/fragment/java/android/support/v4/app/LoaderManager.java
@@ -33,7 +33,7 @@
  * on Android 3.0 or above, this implementation is still used; it does not try
  * to switch to the framework's implementation.  See the framework SDK
  * documentation for a class overview.
- * 
+ *
  * <p>Your activity must derive from {@link FragmentActivity} to use this.
  */
 public abstract class LoaderManager {
@@ -56,7 +56,7 @@
          * transactions while in this call, since it can happen after an
          * activity's state is saved.  See {@link FragmentManager#beginTransaction()
          * FragmentManager.openTransaction()} for further discussion on this.
-         * 
+         *
          * <p>This function is guaranteed to be called prior to the release of
          * the last data that was supplied for this Loader.  At this point
          * you should remove all use of the old data (since it will be released
@@ -100,7 +100,7 @@
          */
         public void onLoaderReset(Loader<D> loader);
     }
-    
+
     /**
      * Ensures a loader is initialized and active.  If the loader doesn't
      * already exist, one is created and (if the activity/fragment is currently
@@ -207,9 +207,9 @@
     boolean mStarted;
     boolean mRetaining;
     boolean mRetainingStarted;
-    
+
     boolean mCreatingLoader;
-    private FragmentHostCallback mHost;
+    FragmentHostCallback mHost;
 
     final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
             Loader.OnLoadCanceledListener<Object> {
@@ -231,13 +231,13 @@
         boolean mListenerRegistered;
 
         LoaderInfo mPendingLoader;
-        
+
         public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
             mId = id;
             mArgs = args;
             mCallbacks = callbacks;
         }
-        
+
         void start() {
             if (mRetaining && mRetainingStarted) {
                 // Our owner is started, but we were being retained from a
@@ -253,7 +253,7 @@
             }
 
             mStarted = true;
-            
+
             if (DEBUG) Log.v(TAG, "  Starting: " + this);
             if (mLoader == null && mCallbacks != null) {
                mLoader = mCallbacks.onCreateLoader(mId, mArgs);
@@ -273,7 +273,7 @@
                 mLoader.startLoading();
             }
         }
-        
+
         void retain() {
             if (DEBUG) Log.v(TAG, "  Retaining: " + this);
             mRetaining = true;
@@ -281,7 +281,7 @@
             mStarted = false;
             mCallbacks = null;
         }
-        
+
         void finishRetain() {
             if (mRetaining) {
                 if (DEBUG) Log.v(TAG, "  Finished Retaining: " + this);
@@ -306,7 +306,7 @@
                 callOnLoadFinished(mLoader, mData);
             }
         }
-        
+
         void reportStart() {
             if (mStarted) {
                 if (mReportNextStart) {
@@ -412,7 +412,7 @@
         @Override
         public void onLoadComplete(Loader<Object> loader, Object data) {
             if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
-            
+
             if (mDestroyed) {
                 if (DEBUG) Log.v(TAG, "  Ignoring load complete -- destroyed");
                 return;
@@ -424,7 +424,7 @@
                 if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
                 return;
             }
-            
+
             LoaderInfo pending = mPendingLoader;
             if (pending != null) {
                 // There is a new request pending and we were just
@@ -437,7 +437,7 @@
                 installLoader(pending);
                 return;
             }
-            
+
             // Notify of the new data so the app can switch out the old data before
             // we try to destroy it.
             if (mData != data || !mHaveData) {
@@ -485,7 +485,7 @@
                 mDeliveredData = true;
             }
         }
-        
+
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder(64);
@@ -525,17 +525,17 @@
             }
         }
     }
-    
+
     LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
         mWho = who;
         mHost = host;
         mStarted = started;
     }
-    
+
     void updateHostController(FragmentHostCallback host) {
         mHost = host;
     }
-    
+
     private LoaderInfo createLoader(int id, Bundle args,
             LoaderManager.LoaderCallbacks<Object> callback) {
         LoaderInfo info = new LoaderInfo(id, args,  callback);
@@ -543,7 +543,7 @@
         info.mLoader = loader;
         return info;
     }
-    
+
     private LoaderInfo createAndInstallLoader(int id, Bundle args,
             LoaderManager.LoaderCallbacks<Object> callback) {
         try {
@@ -555,7 +555,7 @@
             mCreatingLoader = false;
         }
     }
-    
+
     void installLoader(LoaderInfo info) {
         mLoaders.put(info.mId, info);
         if (mStarted) {
@@ -565,23 +565,23 @@
             info.start();
         }
     }
-    
+
     /**
      * Call to initialize a particular ID with a Loader.  If this ID already
      * has a Loader associated with it, it is left unchanged and any previous
      * callbacks replaced with the newly provided ones.  If there is not currently
      * a Loader for the ID, a new one is created and started.
-     * 
+     *
      * <p>This function should generally be used when a component is initializing,
      * to ensure that a Loader it relies on is created.  This allows it to re-use
      * an existing Loader's data if there already is one, so that for example
      * when an {@link Activity} is re-created after a configuration change it
      * does not need to re-create its loaders.
-     * 
+     *
      * <p>Note that in the case where an existing Loader is re-used, the
      * <var>args</var> given here <em>will be ignored</em> because you will
      * continue using the previous Loader.
-     * 
+     *
      * @param id A unique (to this LoaderManager instance) identifier under
      * which to manage the new Loader.
      * @param args Optional arguments that will be propagated to
@@ -596,9 +596,9 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         LoaderInfo info = mLoaders.get(id);
-        
+
         if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
 
         if (info == null) {
@@ -609,30 +609,30 @@
             if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
             info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
         }
-        
+
         if (info.mHaveData && mStarted) {
             // If the loader has already generated its data, report it now.
             info.callOnLoadFinished(info.mLoader, info.mData);
         }
-        
+
         return (Loader<D>)info.mLoader;
     }
-    
+
     /**
      * Call to re-create the Loader associated with a particular ID.  If there
      * is currently a Loader associated with this ID, it will be
      * canceled/stopped/destroyed as appropriate.  A new Loader with the given
      * arguments will be created and its data delivered to you once available.
-     * 
+     *
      * <p>This function does some throttling of Loaders.  If too many Loaders
      * have been created for the given ID but not yet generated their data,
      * new calls to this function will create and return a new Loader but not
      * actually start it until some previous loaders have completed.
-     * 
+     *
      * <p>After calling this function, any previous Loaders associated with
      * this ID will be considered invalid, and you will receive no further
      * data updates from them.
-     * 
+     *
      * @param id A unique (to this LoaderManager instance) identifier under
      * which to manage the new Loader.
      * @param args Optional arguments that will be propagated to
@@ -647,7 +647,7 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         LoaderInfo info = mLoaders.get(id);
         if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
         if (info != null) {
@@ -686,7 +686,7 @@
                             info.mPendingLoader = null;
                         }
                         if (DEBUG) Log.v(TAG, "  Enqueuing as new pending loader");
-                        info.mPendingLoader = createLoader(id, args, 
+                        info.mPendingLoader = createLoader(id, args,
                                 (LoaderManager.LoaderCallbacks<Object>)callback);
                         return (Loader<D>)info.mPendingLoader.mLoader;
                     }
@@ -699,11 +699,11 @@
                 mInactiveLoaders.put(id, info);
             }
         }
-        
+
         info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
         return (Loader<D>)info.mLoader;
     }
-    
+
     /**
      * Rip down, tear apart, shred to pieces a current Loader ID.  After returning
      * from this function, any Loader objects associated with this ID are
@@ -716,7 +716,7 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
         int idx = mLoaders.indexOfKey(id);
         if (idx >= 0) {
@@ -745,7 +745,7 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         LoaderInfo loaderInfo = mLoaders.get(id);
         if (loaderInfo != null) {
             if (loaderInfo.mPendingLoader != null) {
@@ -755,7 +755,7 @@
         }
         return null;
     }
- 
+
     void doStart() {
         if (DEBUG) Log.v(TAG, "Starting in " + this);
         if (mStarted) {
@@ -764,7 +764,7 @@
             Log.w(TAG, "Called doStart when already started: " + this, e);
             return;
         }
-        
+
         mStarted = true;
 
         // Call out to sub classes so they can start their loaders
@@ -773,7 +773,7 @@
             mLoaders.valueAt(i).start();
         }
     }
-    
+
     void doStop() {
         if (DEBUG) Log.v(TAG, "Stopping in " + this);
         if (!mStarted) {
@@ -788,7 +788,7 @@
         }
         mStarted = false;
     }
-    
+
     void doRetain() {
         if (DEBUG) Log.v(TAG, "Retaining in " + this);
         if (!mStarted) {
@@ -804,7 +804,7 @@
             mLoaders.valueAt(i).retain();
         }
     }
-    
+
     void finishRetain() {
         if (mRetaining) {
             if (DEBUG) Log.v(TAG, "Finished Retaining in " + this);
@@ -815,7 +815,7 @@
             }
         }
     }
-    
+
     void doReportNextStart() {
         for (int i = mLoaders.size()-1; i >= 0; i--) {
             mLoaders.valueAt(i).mReportNextStart = true;
@@ -836,7 +836,7 @@
             }
             mLoaders.clear();
         }
-        
+
         if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
         for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
             mInactiveLoaders.valueAt(i).destroy();
diff --git a/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java b/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java
index 78c3e28..188c3b1 100644
--- a/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java
+++ b/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java
@@ -21,7 +21,9 @@
 import android.support.v4.app.test.FragmentTestActivity.ParentFragment;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
+@SmallTest
 public class ChildFragmentStateTest extends ActivityInstrumentationTestCase2<FragmentTestActivity> {
     public ChildFragmentStateTest() {
         super(FragmentTestActivity.class);
diff --git a/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java b/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
index cc884f9..84700ff 100644
--- a/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
+++ b/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
@@ -26,10 +26,12 @@
 import android.support.v4.app.test.FragmentTestActivity.ParentFragment;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.LargeTest;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@LargeTest
 public class NestedFragmentTest extends ActivityInstrumentationTestCase2<FragmentTestActivity> {
 
     ParentFragment mParentFragment;
diff --git a/gradlew b/gradlew
index d1c75a2..9d82f78 100755
--- a/gradlew
+++ b/gradlew
@@ -157,4 +157,4 @@
 eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
 JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
 
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
\ No newline at end of file
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
index 0822e20..639e906 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -50,7 +50,7 @@
 import java.util.List;
 
 /**
- * For API 23 and above, this class is delegating to the framework's {@link AnimatedVectorDrawable}.
+ * For API 24 and above, this class is delegating to the framework's {@link AnimatedVectorDrawable}.
  * For older API version, this class uses {@link android.animation.ObjectAnimator} and
  * {@link android.animation.AnimatorSet} to animate the properties of a
  * {@link VectorDrawableCompat} to create an animated drawable.
@@ -118,7 +118,7 @@
     @Nullable
     public static AnimatedVectorDrawableCompat create(@NonNull Context context,
                                                       @DrawableRes int resId) {
-        if (Build.VERSION.SDK_INT >= 23) {
+        if (Build.VERSION.SDK_INT >= 24) {
             final AnimatedVectorDrawableCompat drawable = new AnimatedVectorDrawableCompat(context);
             drawable.mDelegateDrawable = ResourcesCompat.getDrawable(context.getResources(), resId,
                     context.getTheme());
@@ -165,7 +165,7 @@
 
     /**
      * {@inheritDoc}
-     * <strong>Note</strong> that we don't support constant state when SDK < 23.
+     * <strong>Note</strong> that we don't support constant state when SDK < 24.
      * Make sure you check the return value before using it.
      */
     @Override
@@ -510,12 +510,12 @@
 
         @Override
         public Drawable newDrawable() {
-            throw new IllegalStateException("No constant state support for SDK < 23.");
+            throw new IllegalStateException("No constant state support for SDK < 24.");
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            throw new IllegalStateException("No constant state support for SDK < 23.");
+            throw new IllegalStateException("No constant state support for SDK < 24.");
         }
 
         @Override
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java b/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
index b2b720c..2e50823 100644
--- a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
+++ b/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
@@ -27,6 +27,8 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.ViewCompat;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -47,6 +49,7 @@
 
 import static org.junit.Assert.*;
 
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class AnimatedVectorDrawableTest {
     @Rule public final ActivityTestRule<DrawableStubActivity> mActivityTestRule;
@@ -199,7 +202,7 @@
             public void run() {
                 AnimatedVectorDrawableCompat avd = AnimatedVectorDrawableCompat.create(mContext,
                         R.drawable.animated_color_fill);
-                imageButton.setBackgroundDrawable(avd);
+                ViewCompat.setBackground(imageButton, avd);
                 avd.start();
             }
         });
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
index 40f4c1a..927b5b3 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -54,7 +54,7 @@
 import java.util.Stack;
 
 /**
- * For API 23 and above, this class is delegating to the framework's {@link VectorDrawable}.
+ * For API 24 and above, this class is delegating to the framework's {@link VectorDrawable}.
  * For older API version, this class lets you create a drawable based on an XML vector graphic.
  * <p>
  * VectorDrawableCompat are defined in the same XML format as {@link VectorDrawable}.
@@ -401,7 +401,7 @@
     @Nullable
     public static VectorDrawableCompat create(@NonNull Resources res, @DrawableRes int resId,
                                               @Nullable Theme theme) {
-        if (Build.VERSION.SDK_INT >= 23) {
+        if (Build.VERSION.SDK_INT >= 24) {
             final VectorDrawableCompat drawable = new VectorDrawableCompat();
             drawable.mDelegateDrawable = ResourcesCompat.getDrawable(res, resId, theme);
             drawable.mCachedConstantStateDelegate = new VectorDrawableDelegateState(
@@ -720,7 +720,7 @@
     }
 
     /**
-     * Constant state for delegating the creating drawable job for SDK >= 23.
+     * Constant state for delegating the creating drawable job for SDK >= 24.
      * Instead of creating a VectorDrawable, create a VectorDrawableCompat instance which contains
      * a delegated VectorDrawable instance.
      */
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png
new file mode 100644
index 0000000..a233b1d
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png
new file mode 100644
index 0000000..4ea9aef
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_share.xml b/graphics/drawable/static/tests/res/drawable/vector_icon_share.xml
new file mode 100644
index 0000000..155302c
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable/vector_icon_share.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+
+<vector android:height="24dp" android:viewportHeight="72.0"
+        android:viewportWidth="72.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <group
+            android:scaleX = "2"
+            android:scaleY = "2"
+            android:translateY = "-16"
+            android:translateX = "-36">
+        <path android:fillColor="#FF000000" android:pathData="M60.64,49.29a11.35,11.35 0,0 0,-9.74 5.54L22,39.65a11.14,11.14 0,0 0,0 -7.72L50.87,17.11a11.47,11.47 0,1 0,-1.17 -2.77l-29,14.93a11.36,11.36 0,1 0,0 13L49.71,57.59A11.35,11.35 0,1 0,60.64 49.29ZM60.64,3a8.36,8.36 0,1 1,-8.36 8.36A8.37,8.37 0,0 1,60.64 3ZM11.36,44.13a8.36,8.36 0,1 1,8.36 -8.36A8.37,8.37 0,0 1,11.36 44.13ZM60.64,69A8.36,8.36 0,1 1,69 60.64,8.37 8.37,0 0,1 60.64,69Z"/>
+    </group>
+</vector>
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml b/graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml
new file mode 100644
index 0000000..fd4a52f
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+
+<vector android:height="24dp" android:viewportHeight="72.0"
+        android:viewportWidth="72.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <group
+            android:scaleX = "2"
+            android:scaleY = "2"
+            android:translateX = "-72">
+        <path android:fillColor="#FF000000" android:pathData="M36,69.46h0c-1.56,0 -2.79,-1.17 -4.37,-2.81L4.72,34.93l-0.1,-0.13C2.39,31.48 0,27.47 0,22 0,11.25 8.41,2.54 18.75,2.54c6.18,0 11.85,2.59 17.3,7.91 4.5,-4.06 10,-7.91 17.2,-7.91C63.59,2.54 72,11.25 72,22A19.71,19.71 0,0 1,67.31 34.9L40.41,66.58C38.76,68.3 37.53,69.46 36,69.46ZM7.07,33.06L33.82,64.64A6.8,6.8 0,0 0,36 66.46c0.26,0 1,-0.64 2.21,-1.89L65,33a16.64,16.64 0,0 0,4 -11c0,-7.89 -6,-16.41 -15.75,-16.41C46.57,5.54 41.5,9.42 37,13.62a1.5,1.5 0,0 1,-2.11 -0.06c-5.17,-5.4 -10.46,-8 -16.17,-8C9,5.54 3,14.06 3,22 3,26.59 5,30 7.07,33.06Z"/>
+    </group>
+</vector>
diff --git a/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java b/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java
index 9049b35..8fb9c2d 100644
--- a/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java
+++ b/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java
@@ -71,6 +71,8 @@
             R.drawable.vector_icon_stroke_3,
             R.drawable.vector_icon_scale_1,
             R.drawable.vector_icon_group_clip,
+            R.drawable.vector_icon_share,
+            R.drawable.vector_icon_wishlist,
     };
 
     private static final int[] GOLDEN_IMAGES = new int[]{
@@ -97,6 +99,8 @@
             R.drawable.vector_icon_stroke_3_golden,
             R.drawable.vector_icon_scale_1_golden,
             R.drawable.vector_icon_group_clip_golden,
+            R.drawable.vector_icon_share_golden,
+            R.drawable.vector_icon_wishlist_golden,
     };
 
     private static final int TEST_ICON = R.drawable.vector_icon_create;
diff --git a/samples/Support13Demos/AndroidManifest.xml b/samples/Support13Demos/AndroidManifest.xml
index dfa4e64..01bab26 100644
--- a/samples/Support13Demos/AndroidManifest.xml
+++ b/samples/Support13Demos/AndroidManifest.xml
@@ -87,5 +87,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".view.inputmethod.CommitContentSupport"
+                 android:label="@string/commit_content_support">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv13.SUPPORT13_SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/samples/Support13Demos/res/layout/commit_content.xml b/samples/Support13Demos/res/layout/commit_content.xml
new file mode 100644
index 0000000..414df18
--- /dev/null
+++ b/samples/Support13Demos/res/layout/commit_content.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:background="@android:color/black">
+
+    <WebView
+        android:id="@+id/commit_content_webview"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@android:color/transparent" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="#77000000"
+        android:orientation="vertical">
+
+        <HorizontalScrollView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fadeScrollbars="false"
+            android:scrollbars="horizontal">
+
+            <TableLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+                <TableRow>
+
+                    <TextView
+                        android:layout_column="1"
+                        android:gravity="end"
+                        android:padding="3dip"
+                        android:text="MIME"
+                        android:textColor="@android:color/white"
+                        android:textStyle="bold" />
+
+                    <TextView
+                        android:id="@+id/text_commit_content_mime_types"
+                        android:padding="3dip"
+                        android:textColor="@android:color/white" />
+                </TableRow>
+
+                <TableRow>
+
+                    <TextView
+                        android:layout_column="1"
+                        android:gravity="end"
+                        android:padding="3dip"
+                        android:text="Label"
+                        android:textColor="@android:color/white"
+                        android:textStyle="bold" />
+
+                    <TextView
+                        android:id="@+id/text_commit_content_label"
+                        android:padding="3dip"
+                        android:textColor="@android:color/white" />
+                </TableRow>
+
+                <TableRow>
+
+                    <TextView
+                        android:layout_column="1"
+                        android:gravity="end"
+                        android:padding="3dip"
+                        android:text="URI"
+                        android:textColor="@android:color/white"
+                        android:textStyle="bold" />
+
+                    <TextView
+                        android:id="@+id/text_commit_content_content_uri"
+                        android:padding="3dip"
+                        android:textColor="@android:color/white" />
+                </TableRow>
+
+                <TableRow>
+
+                    <TextView
+                        android:layout_column="1"
+                        android:gravity="end"
+                        android:padding="3dip"
+                        android:text="Link"
+                        android:textColor="@android:color/white"
+                        android:textStyle="bold" />
+
+                    <TextView
+                        android:id="@+id/text_commit_content_link_uri"
+                        android:padding="3dip"
+                        android:textColor="@android:color/white" />
+                </TableRow>
+
+                <TableRow>
+
+                    <TextView
+                        android:layout_column="1"
+                        android:gravity="end"
+                        android:padding="3dip"
+                        android:text="Flags"
+                        android:textColor="@android:color/white"
+                        android:textStyle="bold" />
+
+                    <TextView
+                        android:id="@+id/text_commit_content_link_flags"
+                        android:padding="3dip"
+                        android:textColor="@android:color/white" />
+                </TableRow>
+            </TableLayout>
+        </HorizontalScrollView>
+
+        <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:fadeScrollbars="false"
+            android:scrollbars="vertical">
+
+            <LinearLayout
+                android:id="@+id/commit_content_sample_edit_boxes"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical" />
+        </ScrollView>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/samples/Support13Demos/res/values/strings.xml b/samples/Support13Demos/res/values/strings.xml
index 92316d0..30b6a18 100644
--- a/samples/Support13Demos/res/values/strings.xml
+++ b/samples/Support13Demos/res/values/strings.xml
@@ -36,4 +36,7 @@
     <string name="fragment_state_pager_support">Fragment/State Pager</string>
 
     <string name="action_bar_tabs_pager">Fragment/Action Bar Tabs Pager</string>
+
+    <string name="commit_content_support">View/Input Method/Commit Content</string>
+
 </resources>
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java b/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
index 301a2f8..1bf7691 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
@@ -103,7 +103,7 @@
             mActionBar = activity.getActionBar();
             mViewPager = pager;
             mViewPager.setAdapter(this);
-            mViewPager.setOnPageChangeListener(this);
+            mViewPager.addOnPageChangeListener(this);
         }
 
         public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java
index 0a88a05..3896d9a 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java
@@ -101,7 +101,7 @@
             mActionBar = activity.getActionBar();
             mViewPager = pager;
             mViewPager.setAdapter(this);
-            mViewPager.setOnPageChangeListener(this);
+            mViewPager.addOnPageChangeListener(this);
         }
 
         public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/view/inputmethod/CommitContentSupport.java b/samples/Support13Demos/src/com/example/android/supportv13/view/inputmethod/CommitContentSupport.java
new file mode 100644
index 0000000..29f8a91
--- /dev/null
+++ b/samples/Support13Demos/src/com/example/android/supportv13/view/inputmethod/CommitContentSupport.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.example.android.supportv13.view.inputmethod;
+
+import com.example.android.supportv13.R;
+
+import android.support.v13.view.inputmethod.EditorInfoCompat;
+import android.support.v13.view.inputmethod.InputConnectionCompat;
+import android.support.v13.view.inputmethod.InputContentInfoCompat;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.webkit.WebView;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import static android.widget.LinearLayout.VERTICAL;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class CommitContentSupport extends Activity {
+    private static final String INPUT_CONTENT_INFO_KEY = "COMMIT_CONTENT_INPUT_CONTENT_INFO";
+    private static final String COMMIT_CONTENT_FLAGS_KEY = "COMMIT_CONTENT_FLAGS";
+
+    private static String TAG = "CommitContentSupport";
+
+    private WebView mWebView;
+    private TextView mLabel;
+    private TextView mContentUri;
+    private TextView mLinkUri;
+    private TextView mMimeTypes;
+    private TextView mFlags;
+
+    private InputContentInfoCompat mCurrentInputContentInfo;
+    private int mCurrentFlags;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.commit_content);
+
+        final LinearLayout layout =
+                (LinearLayout) findViewById(R.id.commit_content_sample_edit_boxes);
+
+        // This declares that the IME cannot commit any content with
+        // InputConnectionCompat#commitContent().
+        layout.addView(createEditTextWithContentMimeTypes(null));
+
+        // This declares that the IME can commit contents with
+        // InputConnectionCompat#commitContent() if they match "image/gif".
+        layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/gif"}));
+
+        // This declares that the IME can commit contents with
+        // InputConnectionCompat#commitContent() if they match "image/png".
+        layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/png"}));
+
+        // This declares that the IME can commit contents with
+        // InputConnectionCompat#commitContent() if they match "image/jpeg".
+        layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/jpeg"}));
+
+        // This declares that the IME can commit contents with
+        // InputConnectionCompat#commitContent() if they match "image/webp".
+        layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/webp"}));
+
+        // This declares that the IME can commit contents with
+        // InputConnectionCompat#commitContent() if they match "image/png", "image/gif",
+        // "image/jpeg", or "image/webp".
+        layout.addView(createEditTextWithContentMimeTypes(
+                new String[]{"image/png", "image/gif", "image/jpeg", "image/webp"}));
+
+        mWebView = (WebView) findViewById(R.id.commit_content_webview);
+        mMimeTypes = (TextView) findViewById(R.id.text_commit_content_mime_types);
+        mLabel = (TextView) findViewById(R.id.text_commit_content_label);
+        mContentUri = (TextView) findViewById(R.id.text_commit_content_content_uri);
+        mLinkUri = (TextView) findViewById(R.id.text_commit_content_link_uri);
+        mFlags = (TextView) findViewById(R.id.text_commit_content_link_flags);
+
+        if (savedInstanceState != null) {
+            final InputContentInfoCompat previousInputContentInfo = InputContentInfoCompat.wrap(
+                    savedInstanceState.getParcelable(INPUT_CONTENT_INFO_KEY));
+            final int previousFlags = savedInstanceState.getInt(COMMIT_CONTENT_FLAGS_KEY);
+            if (previousInputContentInfo != null) {
+                onCommitContentInternal(previousInputContentInfo, previousFlags);
+            }
+        }
+    }
+
+    private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags,
+            Bundle opts, String[] contentMimeTypes) {
+        // Clear the temporary permission (if any).  See below about why we do this here.
+        try {
+            if (mCurrentInputContentInfo != null) {
+                mCurrentInputContentInfo.releasePermission();
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "InputContentInfo#releasePermission() failed.", e);
+        } finally {
+            mCurrentInputContentInfo = null;
+        }
+
+        mWebView.loadUrl("about:blank");
+        mMimeTypes.setText("");
+        mContentUri.setText("");
+        mLabel.setText("");
+        mLinkUri.setText("");
+        mFlags.setText("");
+
+        boolean supported = false;
+        for (final String mimeType : contentMimeTypes) {
+            if (inputContentInfo.getDescription().hasMimeType(mimeType)) {
+                supported = true;
+                break;
+            }
+        }
+        if (!supported) {
+            return false;
+        }
+
+        return onCommitContentInternal(inputContentInfo, flags);
+    }
+
+    private boolean onCommitContentInternal(InputContentInfoCompat inputContentInfo, int flags) {
+        if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+            try {
+                inputContentInfo.requestPermission();
+            } catch (Exception e) {
+                Log.e(TAG, "InputContentInfo#requestPermission() failed.", e);
+                return false;
+            }
+        }
+
+        mMimeTypes.setText(
+                Arrays.toString(inputContentInfo.getDescription().filterMimeTypes("*/*")));
+        mContentUri.setText(inputContentInfo.getContentUri().toString());
+        mLabel.setText(inputContentInfo.getDescription().getLabel());
+        Uri linkUri = inputContentInfo.getLinkUri();
+        mLinkUri.setText(linkUri != null ? linkUri.toString() : "null");
+        mFlags.setText(flagsToString(flags));
+        mWebView.loadUrl(inputContentInfo.getContentUri().toString());
+        mWebView.setBackgroundColor(Color.TRANSPARENT);
+
+        // Due to the asynchronous nature of WebView, it is a bit too early to call
+        // inputContentInfo.releasePermission() here. Hence we call IC#releasePermission() when this
+        // method is called next time.  Note that calling IC#releasePermission() is just to be a
+        // good citizen. Even if we failed to call that method, the system would eventually revoke
+        // the permission sometime after inputContentInfo object gets garbage-collected.
+        mCurrentInputContentInfo = inputContentInfo;
+        mCurrentFlags = flags;
+
+        return true;
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle savedInstanceState) {
+        if (mCurrentInputContentInfo != null) {
+            savedInstanceState.putParcelable(INPUT_CONTENT_INFO_KEY,
+                    (Parcelable) mCurrentInputContentInfo.unwrap());
+            savedInstanceState.putInt(COMMIT_CONTENT_FLAGS_KEY, mCurrentFlags);
+        }
+        mCurrentInputContentInfo = null;
+        mCurrentFlags = 0;
+        super.onSaveInstanceState(savedInstanceState);
+    }
+
+    /**
+     * Creates a new instance of {@link EditText} that is configured to specify the given content
+     * MIME types to {@link EditorInfo#contentMimeTypes} so that developers
+     * can locally test how the current input method behaves for such content MIME types.
+     *
+     * @param contentMimeTypes A {@link String} array that indicates the supported content MIME
+     *                         types
+     * @return a new instance of {@link EditText}, which specifies
+     * {@link EditorInfo#contentMimeTypes} with the given content
+     * MIME types
+     */
+    private EditText createEditTextWithContentMimeTypes(String[] contentMimeTypes) {
+        final CharSequence hintText;
+        final String[] mimeTypes;  // our own copy of contentMimeTypes.
+        if (contentMimeTypes == null || contentMimeTypes.length == 0) {
+            hintText = "MIME: []";
+            mimeTypes = new String[0];
+        } else {
+            hintText = "MIME: " + Arrays.toString(contentMimeTypes);
+            mimeTypes = Arrays.copyOf(contentMimeTypes, contentMimeTypes.length);
+        }
+        EditText exitText = new EditText(this) {
+            @Override
+            public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
+                final InputConnection ic = super.onCreateInputConnection(editorInfo);
+                EditorInfoCompat.setContentMimeTypes(editorInfo, mimeTypes);
+                final InputConnectionCompat.OnCommitContentListener callback =
+                        new InputConnectionCompat.OnCommitContentListener() {
+                            @Override
+                            public boolean onCommitContent(InputContentInfoCompat inputContentInfo,
+                                    int flags, Bundle opts) {
+                                return CommitContentSupport.this.onCommitContent(
+                                        inputContentInfo, flags, opts, mimeTypes);
+                            }
+                        };
+                return InputConnectionCompat.createWrapper(ic, editorInfo, callback);
+            }
+        };
+        exitText.setHint(hintText);
+        exitText.setTextColor(Color.WHITE);
+        exitText.setHintTextColor(Color.WHITE);
+        return exitText;
+    }
+
+    /**
+     * Converts {@code flags} specified in {@link InputConnectionCompat#commitContent(
+     *InputConnection, EditorInfo, InputContentInfoCompat, int, Bundle)} to a human readable
+     * string.
+     *
+     * @param flags the 2nd parameter of
+     *              {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+     *              InputContentInfoCompat, int, Bundle)}
+     * @return a human readable string that corresponds to the given {@code flags}
+     */
+    private static String flagsToString(int flags) {
+        final ArrayList<String> tokens = new ArrayList<>();
+        if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+            tokens.add("INPUT_CONTENT_GRANT_READ_URI_PERMISSION");
+            flags &= ~InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
+        }
+        if (flags != 0) {
+            tokens.add("0x" + Integer.toHexString(flags));
+        }
+        return TextUtils.join(" | ", tokens);
+    }
+
+}
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
index 4be078b..8c9d40c 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
@@ -23,7 +23,6 @@
 import android.os.Bundle;
 import android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat;
 import android.support.v4.view.accessibility.AccessibilityManagerCompat;
-import android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.TextView;
 import android.widget.Toast;
@@ -85,7 +84,7 @@
         // platform API version is lower and the called API is not available no listener
         // is added and you will not receive a call of onAccessibilityStateChanged.
         AccessibilityManagerCompat.addAccessibilityStateChangeListener(mAccessibilityManager,
-                new AccessibilityStateChangeListenerCompat() {
+                new AccessibilityManagerCompat.AccessibilityStateChangeListener() {
             @Override
             public void onAccessibilityStateChanged(boolean enabled) {
                 Toast.makeText(AccessibilityManagerSupportActivity.this,
@@ -119,7 +118,8 @@
                         R.string.accessibility_manager_enabled_service,
                         resolveInfo.loadLabel(getPackageManager()),
                         AccessibilityServiceInfoCompat.feedbackTypeToString(service.feedbackType),
-                        AccessibilityServiceInfoCompat.getDescription(service),
+                        AccessibilityServiceInfoCompat.loadDescription(
+                                service, getPackageManager()),
                         AccessibilityServiceInfoCompat.getSettingsActivityName(service));
                 builder.append(serviceDescription);
             }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java
index 8def8af..a9f4439 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java
@@ -16,21 +16,22 @@
 
 package com.example.android.supportv4.app;
 
-import com.example.android.supportv4.R;
-
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-
-import android.app.Activity;
+import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import com.example.android.supportv4.R;
+
 /**
  * Demonstrates a fragment that can be configured through both Bundle arguments
  * and layout attributes.
@@ -71,11 +72,11 @@
          * Parse attributes during inflation from a view hierarchy into the
          * arguments we handle.
          */
-        @Override public void onInflate(Activity activity, AttributeSet attrs,
-                Bundle savedInstanceState) {
-            super.onInflate(activity, attrs, savedInstanceState);
+        @Override
+        public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
+            super.onInflate(context, attrs, savedInstanceState);
 
-            TypedArray a = activity.obtainStyledAttributes(attrs,
+            TypedArray a = context.obtainStyledAttributes(attrs,
                     R.styleable.FragmentArguments);
             mLabel = a.getText(R.styleable.FragmentArguments_android_label);
             a.recycle();
@@ -85,7 +86,8 @@
          * During creation, if arguments have been supplied to the fragment
          * then parse those out.
          */
-        @Override public void onCreate(Bundle savedInstanceState) {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
 
             Bundle args = getArguments();
@@ -100,12 +102,14 @@
         /**
          * Create the view for this fragment, using the arguments given to it.
          */
-        @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                 Bundle savedInstanceState) {
             View v = inflater.inflate(R.layout.hello_world, container, false);
             View tv = v.findViewById(R.id.text);
             ((TextView)tv).setText(mLabel != null ? mLabel : "(no label)");
-            tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
+            ViewCompat.setBackground(
+                    tv, ContextCompat.getDrawable(getContext(), android.R.drawable.gallery_thumb));
             return v;
         }
     }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java
index cf734d7..66a1b2d 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java
@@ -15,8 +15,6 @@
  */
 package com.example.android.supportv4.app;
 
-import com.example.android.supportv4.R;
-
 import android.content.Context;
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
@@ -28,6 +26,8 @@
 import android.widget.TabHost;
 import android.widget.TabWidget;
 
+import com.example.android.supportv4.R;
+
 import java.util.ArrayList;
 
 /**
@@ -125,7 +125,7 @@
             mViewPager = pager;
             mTabHost.setOnTabChangedListener(this);
             mViewPager.setAdapter(this);
-            mViewPager.setOnPageChangeListener(this);
+            mViewPager.addOnPageChangeListener(this);
         }
 
         public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
index 312aba4..d858fae 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
@@ -37,8 +37,6 @@
 import android.support.v4.content.pm.ActivityInfoCompat;
 import android.support.v4.view.MenuItemCompat;
 import android.support.v4.widget.SearchViewCompat;
-import android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat;
-import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -411,8 +409,6 @@
         // If non-null, this is the current filter the user has provided.
         String mCurFilter;
 
-        OnQueryTextListenerCompat mOnQueryTextListenerCompat;
-
         @Override public void onActivityCreated(Bundle savedInstanceState) {
             super.onActivityCreated(savedInstanceState);
 
@@ -444,18 +440,23 @@
             final View searchView = SearchViewCompat.newSearchView(getActivity());
             if (searchView != null) {
                 SearchViewCompat.setOnQueryTextListener(searchView,
-                        new OnQueryTextListenerCompat() {
-                    @Override
-                    public boolean onQueryTextChange(String newText) {
-                        // Called when the action bar search text has changed.  Since this
-                        // is a simple array adapter, we can just have it do the filtering.
-                        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
-                        mAdapter.getFilter().filter(mCurFilter);
-                        return true;
-                    }
-                });
+                        new SearchViewCompat.OnQueryTextListener() {
+                            @Override
+                            public boolean onQueryTextChange(String newText) {
+                                // Called when the action bar search text has changed.  Since this
+                                // is a simple array adapter, we can just have it do the filtering.
+                                mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
+                                mAdapter.getFilter().filter(mCurFilter);
+                                return true;
+                            }
+
+                            @Override
+                            public boolean onQueryTextSubmit(String query) {
+                                return false;
+                            }
+                        });
                 SearchViewCompat.setOnCloseListener(searchView,
-                        new OnCloseListenerCompat() {
+                        new SearchViewCompat.OnCloseListener() {
                             @Override
                             public boolean onClose() {
                                 if (!TextUtils.isEmpty(SearchViewCompat.getQuery(searchView))) {
@@ -463,8 +464,7 @@
                                 }
                                 return true;
                             }
-                    
-                });
+                        });
                 MenuItemCompat.setActionView(item, searchView);
             }
         }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
index f26e038..b408349 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
@@ -29,8 +29,9 @@
 import android.widget.ArrayAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
-import com.example.android.supportv4.Shakespeare;
+
 import com.example.android.supportv4.R;
+import com.example.android.supportv4.Shakespeare;
 
 /**
  * This example illustrates a common usage of SlidingPaneLayout in the Android support library.
@@ -98,7 +99,7 @@
          * as the left pane contains content one level up in the navigation hierarchy.
          */
         if (item.getItemId() == android.R.id.home && !mSlidingLayout.isOpen()) {
-            mSlidingLayout.smoothSlideOpen();
+            mSlidingLayout.openPane();
             return true;
         }
         return super.onOptionsItemSelected(item);
@@ -114,7 +115,7 @@
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
             mContent.setText(Shakespeare.DIALOGUE[position]);
             mActionBar.setTitle(Shakespeare.TITLES[position]);
-            mSlidingLayout.smoothSlideClosed();
+            mSlidingLayout.closePane();
         }
     }
 
@@ -206,7 +207,7 @@
 
         @Override
         public void onFirstLayout() {
-            if (mSlidingLayout.canSlide() && !mSlidingLayout.isOpen()) {
+            if (mSlidingLayout.isSlideable() && !mSlidingLayout.isOpen()) {
                 onPanelClosed();
             } else {
                 onPanelOpened();
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 066afc3..a416f07 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -389,8 +389,17 @@
         </activity>
 
         <activity android:name=".widget.LinearLayoutManagerActivity"
-                  android:label="@string/linear_layout_manager"
-                  android:theme="@style/Theme.AppCompat">
+            android:label="@string/linear_layout_manager"
+            android:theme="@style/Theme.AppCompat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".widget.LinearLayoutManagerJankActivity"
+            android:label="@string/linear_layout_manager"
+            android:theme="@style/Theme.AppCompat">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 4bf046e..ad87a6a 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -144,6 +144,9 @@
     <string name="enableAnimations">Animate</string>
     <string name="enablePredictiveAnimations">Predictive</string>
     <string name="enableInPlaceChange">In Place Change</string>
+    <string name="enable_inflate_slowdown">Slow inflate</string>
+    <string name="enable_bind_slowdown">Slow bind</string>
+    <string name="enable_prefetch">Prefetch</string>
     <string name="add_item">Add</string>
     <string name="delete_item">Del</string>
     <string name="add_delete_item">A+D</string>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java
index e82aa3a..0759e33 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java
@@ -29,6 +29,7 @@
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.CursorLoader;
 import android.support.v4.content.Loader;
+import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.ResourceCursorAdapter;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.graphics.Palette;
@@ -190,12 +191,12 @@
                 ImageView imageView = (ImageView) view.findViewById(R.id.image);
                 imageView.setImageDrawable(null);
 
-                view.findViewById(R.id.text_vibrant).setBackgroundDrawable(null);
-                view.findViewById(R.id.text_muted).setBackgroundDrawable(null);
-                view.findViewById(R.id.text_light_vibrant).setBackgroundDrawable(null);
-                view.findViewById(R.id.text_light_muted).setBackgroundDrawable(null);
-                view.findViewById(R.id.text_dark_vibrant).setBackgroundDrawable(null);
-                view.findViewById(R.id.text_dark_muted).setBackgroundDrawable(null);
+                ViewCompat.setBackground(view.findViewById(R.id.text_vibrant), null);
+                ViewCompat.setBackground(view.findViewById(R.id.text_muted), null);
+                ViewCompat.setBackground(view.findViewById(R.id.text_light_vibrant), null);
+                ViewCompat.setBackground(view.findViewById(R.id.text_light_muted), null);
+                ViewCompat.setBackground(view.findViewById(R.id.text_dark_vibrant), null);
+                ViewCompat.setBackground(view.findViewById(R.id.text_dark_muted), null);
 
                 final long id = cursor.getLong(
                         cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
index 7482e3e..914f1e8 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
@@ -16,11 +16,11 @@
 
 package com.example.android.supportv7.widget;
 
-import com.example.android.supportv7.widget.decorator.DividerItemDecoration;
-
 import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.DividerItemDecoration;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
+
 import com.example.android.supportv7.R;
 import com.example.android.supportv7.widget.util.ConfigToggle;
 
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerJankActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerJankActivity.java
new file mode 100644
index 0000000..1709d3e
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerJankActivity.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.widget;
+
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.ViewGroup;
+
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+
+/**
+ * A configurably janky activity that uses {@link LinearLayoutManager}.
+ */
+public class LinearLayoutManagerJankActivity extends LinearLayoutManagerActivity {
+
+    private boolean mBindSlowdownEnabled = true;
+    private boolean mInflateSlowdownEnabled = true;
+
+    /**
+     * Spin wait. Used instead of sleeping so a core is used up for the duration, and so
+     * traces/sampled profiling show the sections as expensive, and not just a scheduling mistake.
+     */
+    private static void spinWaitMs(long ms) {
+        long start = System.nanoTime();
+        while (System.nanoTime() - start < ms * 1000L * 1000L);
+    }
+
+    @Override
+    protected RecyclerView.Adapter createAdapter() {
+        return new SimpleStringAdapter(this, Cheeses.sCheeseStrings) {
+            @Override
+            public void onBindViewHolder(ViewHolder holder, int position) {
+                super.onBindViewHolder(holder, position);
+                if (mBindSlowdownEnabled) spinWaitMs(8);
+            }
+
+            @Override
+            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+                if (mInflateSlowdownEnabled) spinWaitMs(4);
+                return super.onCreateViewHolder(parent, viewType);
+            }
+        };
+    }
+
+    @Override
+    ConfigToggle[] createConfigToggles() {
+        return new ConfigToggle[]{
+                new ConfigToggle(this, R.string.enable_bind_slowdown) {
+                    @Override
+                    public boolean isChecked() { return mBindSlowdownEnabled; }
+
+                    @Override
+                    public void onChange(boolean newValue) { mBindSlowdownEnabled = newValue; }
+                },
+                new ConfigToggle(this, R.string.enable_inflate_slowdown) {
+                    @Override
+                    public boolean isChecked() { return mInflateSlowdownEnabled; }
+
+                    @Override
+                    public void onChange(boolean newValue) { mInflateSlowdownEnabled = newValue; }
+                },
+                new ConfigToggle(this, R.string.enable_prefetch) {
+                    @Override
+                    public boolean isChecked() { return mLayoutManager.isItemPrefetchEnabled(); }
+
+                    @Override
+                    public void onChange(boolean newValue) {
+                        mLayoutManager.setItemPrefetchEnabled(newValue);
+                    }
+                },
+        };
+    }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
index 38b50bd..a49ddbe 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
@@ -17,14 +17,11 @@
 
 package com.example.android.supportv7.widget;
 
-import com.example.android.supportv7.Cheeses;
-import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
-import com.example.android.supportv7.widget.decorator.DividerItemDecoration;
-
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
 import android.support.v4.view.MenuItemCompat;
+import android.support.v7.widget.DividerItemDecoration;
 import android.support.v7.widget.RecyclerView;
 import android.util.DisplayMetrics;
 import android.view.Menu;
@@ -32,6 +29,9 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+
 public class RecyclerViewActivity extends Activity {
 
     private static final String TAG = "RecyclerViewActivity";
@@ -68,7 +68,7 @@
                 return vh;
             }
         });
-        rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
+        rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
         setContentView(rv);
         mRecyclerView = rv;
     }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java
deleted file mode 100644
index 4386f4f..0000000
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.supportv7.widget.decorator;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-public class DividerItemDecoration extends RecyclerView.ItemDecoration {
-
-    private static final int[] ATTRS = new int[]{
-            android.R.attr.listDivider
-    };
-
-    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
-
-    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
-
-    private Drawable mDivider;
-
-    private int mOrientation;
-
-    public DividerItemDecoration(Context context, int orientation) {
-        final TypedArray a = context.obtainStyledAttributes(ATTRS);
-        mDivider = a.getDrawable(0);
-        a.recycle();
-        setOrientation(orientation);
-    }
-
-    public void setOrientation(int orientation) {
-        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
-            throw new IllegalArgumentException("invalid orientation");
-        }
-        mOrientation = orientation;
-    }
-
-    @Override
-    public void onDraw(Canvas c, RecyclerView parent) {
-        if (mOrientation == VERTICAL_LIST) {
-            drawVertical(c, parent);
-        } else {
-            drawHorizontal(c, parent);
-        }
-    }
-
-    public void drawVertical(Canvas c, RecyclerView parent) {
-        final int left = parent.getPaddingLeft();
-        final int right = parent.getWidth() - parent.getPaddingRight();
-
-        final int childCount = parent.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = parent.getChildAt(i);
-            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
-                    .getLayoutParams();
-            final int top = child.getBottom() + params.bottomMargin +
-                    Math.round(ViewCompat.getTranslationY(child));
-            final int bottom = top + mDivider.getIntrinsicHeight();
-            mDivider.setBounds(left, top, right, bottom);
-            mDivider.draw(c);
-        }
-    }
-
-    public void drawHorizontal(Canvas c, RecyclerView parent) {
-        final int top = parent.getPaddingTop();
-        final int bottom = parent.getHeight() - parent.getPaddingBottom();
-
-        final int childCount = parent.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = parent.getChildAt(i);
-            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
-                    .getLayoutParams();
-            final int left = child.getRight() + params.rightMargin +
-                    Math.round(ViewCompat.getTranslationX(child));
-            final int right = left + mDivider.getIntrinsicHeight();
-            mDivider.setBounds(left, top, right, bottom);
-            mDivider.draw(c);
-        }
-    }
-
-    @Override
-    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
-        if (mOrientation == VERTICAL_LIST) {
-            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
-        } else {
-            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
-        }
-    }
-}
diff --git a/samples/SupportDesignDemos/Android.mk b/samples/SupportDesignDemos/Android.mk
index de9e302..8ae120e 100644
--- a/samples/SupportDesignDemos/Android.mk
+++ b/samples/SupportDesignDemos/Android.mk
@@ -28,16 +28,19 @@
         android-support-v4 \
         android-support-v7-appcompat \
         android-support-v7-recyclerview \
+        android-support-transition \
         android-support-design
 LOCAL_RESOURCE_DIR = \
         $(LOCAL_PATH)/res \
         frameworks/support/v7/appcompat/res \
         frameworks/support/v7/recyclerview/res \
+        frameworks/support/transition/res \
         frameworks/support/design/res
 LOCAL_AAPT_FLAGS := \
         --auto-add-overlay \
         --extra-packages android.support.v7.appcompat \
         --extra-packages android.support.v7.recyclerview \
+        --extra-packages android.support.transition \
         --extra-packages android.support.design \
         --no-version-vectors
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/samples/SupportDesignDemos/AndroidManifest.xml b/samples/SupportDesignDemos/AndroidManifest.xml
index 0ee0470..13071ea 100644
--- a/samples/SupportDesignDemos/AndroidManifest.xml
+++ b/samples/SupportDesignDemos/AndroidManifest.xml
@@ -291,6 +291,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".widget.BottomNavigationViewUsage"
+                  android:label="@string/design_bottom_navigation_view">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.support.design.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".widget.CoordinatorLayoutInset"
                   android:label="@string/design_coordinatorlayout_insetView"
                   android:theme="@style/Theme.Design">
diff --git a/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml
new file mode 100644
index 0000000..83e7314
--- /dev/null
+++ b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <Button
+            android:id="@+id/button_disable"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/bottomnavigation_disable"/>
+
+    <Button
+        android:id="@+id/button_add"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/bottomnavigation_add"
+        android:layout_below="@+id/button_disable"/>
+
+    <Button
+        android:id="@+id/button_remove"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/bottomnavigation_remove"
+        android:layout_below="@+id/button_add"/>
+
+    <Button
+        android:id="@+id/button_tint"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/bottomnavigation_tint"
+        android:layout_below="@+id/button_remove"/>
+
+    <android.support.design.widget.BottomNavigationView
+            android:id="@+id/bottom_navigation"
+            android:layout_width="match_parent"
+            android:layout_height="56dp"
+            android:layout_gravity="bottom"
+            android:background="#eee"
+            android:layout_alignParentBottom="true"
+            app:menu="@menu/sample_bottom_menu"/>
+
+</RelativeLayout>
diff --git a/samples/SupportDesignDemos/res/values/strings.xml b/samples/SupportDesignDemos/res/values/strings.xml
index a6a1bc9..95900ca 100644
--- a/samples/SupportDesignDemos/res/values/strings.xml
+++ b/samples/SupportDesignDemos/res/values/strings.xml
@@ -124,6 +124,7 @@
     <string name="design_bottom_navigation_view">Bottom navigation view</string>
 
     <string name="bottomnavigation_disable">Disable item</string>
-    <string name="bottomnavigation_add">Add item</string>
+    <string name="bottomnavigation_add">Add an item</string>
+    <string name="bottomnavigation_remove">Remove an item</string>
     <string name="bottomnavigation_tint">Toggle tint</string>
 </resources>
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java
new file mode 100644
index 0000000..72b50db
--- /dev/null
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.support.design.widget;
+
+import android.content.res.ColorStateList;
+import android.os.Bundle;
+import android.support.design.widget.BottomNavigationView;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+
+import com.example.android.support.design.R;
+
+/**
+ * This demonstrates idiomatic usage of the bottom navigation widget.
+ */
+public class BottomNavigationViewUsage extends AppCompatActivity {
+    private ColorStateList mOriginalTint;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.design_bottom_navigation_view);
+        Button buttonDisable = (Button) findViewById(R.id.button_disable);
+        final BottomNavigationView bottom =
+                (BottomNavigationView) findViewById(R.id.bottom_navigation);
+        mOriginalTint = bottom.getItemIconTintList();
+        buttonDisable.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                bottom.getMenu().getItem(0).setEnabled(!bottom.getMenu().getItem(0).isEnabled());
+            }
+        });
+        Button buttonAdd = (Button) findViewById(R.id.button_add);
+        buttonAdd.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                if (bottom.getMenu().size() < 5) {
+                    MenuItem item = bottom.getMenu().add("Bananas");
+                    item.setIcon(android.R.drawable.ic_lock_power_off);
+                }
+            }
+        });
+        Button buttonRemove = (Button) findViewById(R.id.button_remove);
+        buttonRemove.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                bottom.getMenu().removeItem(0);
+            }
+        });
+        Button buttonTint = (Button) findViewById(R.id.button_tint);
+        buttonTint.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                if (bottom.getItemIconTintList() == null) {
+                    bottom.setItemIconTintList(mOriginalTint);
+                } else {
+                    bottom.setItemIconTintList(null);
+                }
+            }
+        });
+    }
+}
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
index ea8b4d6..12e1842 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
@@ -20,6 +20,7 @@
 import android.support.design.widget.TabLayout;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
+import android.support.v4.widget.TextViewCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.view.Gravity;
@@ -147,7 +148,7 @@
             final TextView tv = new TextView(container.getContext());
             tv.setText(getPageTitle(position));
             tv.setGravity(Gravity.CENTER);
-            tv.setTextAppearance(tv.getContext(), R.style.TextAppearance_AppCompat_Title);
+            TextViewCompat.setTextAppearance(tv, R.style.TextAppearance_AppCompat_Title);
             container.addView(tv, ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.MATCH_PARENT);
 
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java
index 26b6108..387e1a0 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java
@@ -23,6 +23,7 @@
 import android.support.design.widget.TabLayout;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
+import android.support.v4.widget.TextViewCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.view.Gravity;
@@ -166,7 +167,7 @@
             final TextView tv = new TextView(container.getContext());
             tv.setText(getPageTitle(position));
             tv.setGravity(Gravity.CENTER);
-            tv.setTextAppearance(tv.getContext(), R.style.TextAppearance_AppCompat_Title);
+            TextViewCompat.setTextAppearance(tv, R.style.TextAppearance_AppCompat_Title);
             container.addView(tv, ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.MATCH_PARENT);
 
diff --git a/samples/SupportPreferenceDemos/Android.mk b/samples/SupportPreferenceDemos/Android.mk
new file mode 100644
index 0000000..f131aa0
--- /dev/null
+++ b/samples/SupportPreferenceDemos/Android.mk
@@ -0,0 +1,61 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build the samples.
+# We need to add some special AAPT flags to generate R classes
+# for resources that are included from the libraries.
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := SupportPreferenceDemos
+LOCAL_MODULE_TAGS := samples
+
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 14
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-v4 \
+    android-support-v7-appcompat \
+    android-support-v7-preference \
+    android-support-v7-recyclerview \
+    android-support-v14-preference \
+    android-support-v17-leanback \
+    android-support-v17-preference-leanback \
+
+LOCAL_RESOURCE_DIR = \
+    $(LOCAL_PATH)/res \
+    frameworks/support/v7/appcompat/res \
+    frameworks/support/v7/preference/res \
+    frameworks/support/v7/recyclerview/res \
+    frameworks/support/v14/preference/res \
+    frameworks/support/v17/leanback/res \
+    frameworks/support/v17/preference-leanback/res
+
+LOCAL_AAPT_FLAGS := \
+        --auto-add-overlay \
+        --extra-packages android.support.v7.appcompat \
+        --extra-packages android.support.v7.preference \
+        --extra-packages android.support.v7.recyclerview \
+        --extra-packages android.support.v14.preference \
+        --extra-packages android.support.v17.leanback \
+        --extra-packages android.support.v17.preference \
+        --no-version-vectors
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
diff --git a/samples/SupportPreferenceDemos/proguard.flags b/samples/SupportPreferenceDemos/proguard.flags
new file mode 100644
index 0000000..9ebd737
--- /dev/null
+++ b/samples/SupportPreferenceDemos/proguard.flags
@@ -0,0 +1,7 @@
+-keep public class * extends android.support.design.widget.CoordinatorLayout$Behavior {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keep public class * extends android.support.v7.widget.LinearLayoutManager {
+    public <init>(android.content.Context, android.util.AttributeSet, int, int);
+}
diff --git a/samples/SupportTransitionDemos/Android.mk b/samples/SupportTransitionDemos/Android.mk
index 1d077a2..abc1ad9 100644
--- a/samples/SupportTransitionDemos/Android.mk
+++ b/samples/SupportTransitionDemos/Android.mk
@@ -21,6 +21,8 @@
 LOCAL_PACKAGE_NAME := SupportTransitionDemos
 LOCAL_MODULE_TAGS := samples
 LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 14
+LOCAL_DEX_PREOPT := false
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_STATIC_JAVA_LIBRARIES := \
         android-support-v4 \
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index bfdb396..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
-    android-support-v4 \
-    mockito-target
-
-LOCAL_PACKAGE_NAME := AndroidSupportTests
-
-include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
deleted file mode 100644
index 35314ae..0000000
--- a/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.tests">
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-
-        <activity android:name="android.support.tests.GrantActivity" android:label="_GrantActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-    </application>
-
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="android.support.tests" />
-
-</manifest>
diff --git a/transition/ics/android/support/transition/TransitionManagerPort.java b/transition/ics/android/support/transition/TransitionManagerPort.java
index 7857f57..d6ca154 100644
--- a/transition/ics/android/support/transition/TransitionManagerPort.java
+++ b/transition/ics/android/support/transition/TransitionManagerPort.java
@@ -132,7 +132,7 @@
 
         if (runningTransitions != null && runningTransitions.size() > 0) {
             for (TransitionPort runningTransition : runningTransitions) {
-                runningTransition.pause();
+                runningTransition.pause(sceneRoot);
             }
         }
 
@@ -397,7 +397,7 @@
             ArrayList<TransitionPort> runningTransitions = getRunningTransitions().get(mSceneRoot);
             if (runningTransitions != null && runningTransitions.size() > 0) {
                 for (TransitionPort runningTransition : runningTransitions) {
-                    runningTransition.resume();
+                    runningTransition.resume(mSceneRoot);
                 }
             }
             mTransition.clearValues(true);
@@ -430,7 +430,7 @@
             mTransition.captureValues(mSceneRoot, false);
             if (previousRunningTransitions != null) {
                 for (TransitionPort runningTransition : previousRunningTransitions) {
-                    runningTransition.resume();
+                    runningTransition.resume(mSceneRoot);
                 }
             }
             mTransition.playTransition(mSceneRoot);
diff --git a/transition/ics/android/support/transition/TransitionPort.java b/transition/ics/android/support/transition/TransitionPort.java
index 31b4221..f6c3346 100644
--- a/transition/ics/android/support/transition/TransitionPort.java
+++ b/transition/ics/android/support/transition/TransitionPort.java
@@ -343,7 +343,8 @@
                             view = start.view;
                         }
                         if (animator != null) {
-                            AnimationInfo info = new AnimationInfo(view, getName(), infoValues);
+                            AnimationInfo info = new AnimationInfo(view, getName(),
+                                    WindowIdPort.getWindowId(sceneRoot), infoValues);
                             runningAnimators.put(animator, info);
                             mAnimators.add(animator);
                         }
@@ -788,13 +789,17 @@
      *
      * @hide
      */
-    public void pause() {
+    public void pause(View sceneRoot) {
         if (!mEnded) {
             ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
             int numOldAnims = runningAnimators.size();
+            WindowIdPort windowId = WindowIdPort.getWindowId(sceneRoot);
             for (int i = numOldAnims - 1; i >= 0; i--) {
-                Animator anim = runningAnimators.keyAt(i);
-//                anim.pause();
+                AnimationInfo info = runningAnimators.valueAt(i);
+                if (info.view != null && windowId.equals(info.windowId)) {
+                    Animator anim = runningAnimators.keyAt(i);
+                    anim.cancel(); // pause() is API Level 19
+                }
             }
             if (mListeners != null && mListeners.size() > 0) {
                 ArrayList<TransitionListener> tmpListeners =
@@ -815,14 +820,18 @@
      *
      * @hide
      */
-    public void resume() {
+    public void resume(View sceneRoot) {
         if (mPaused) {
             if (!mEnded) {
                 ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
                 int numOldAnims = runningAnimators.size();
+                WindowIdPort windowId = WindowIdPort.getWindowId(sceneRoot);
                 for (int i = numOldAnims - 1; i >= 0; i--) {
-                    Animator anim = runningAnimators.keyAt(i);
-//                    anim.resume();
+                    AnimationInfo info = runningAnimators.valueAt(i);
+                    if (info.view != null && windowId.equals(info.windowId)) {
+                        Animator anim = runningAnimators.keyAt(i);
+                        anim.end(); // resume() is API Level 19
+                    }
                 }
                 if (mListeners != null && mListeners.size() > 0) {
                     ArrayList<TransitionListener> tmpListeners =
@@ -1211,10 +1220,13 @@
 
         TransitionValues values;
 
-        AnimationInfo(View view, String name, TransitionValues values) {
+        WindowIdPort windowId;
+
+        AnimationInfo(View view, String name, WindowIdPort windowId, TransitionValues values) {
             this.view = view;
             this.name = name;
             this.values = values;
+            this.windowId = windowId;
         }
     }
 
diff --git a/transition/ics/android/support/transition/TransitionSetPort.java b/transition/ics/android/support/transition/TransitionSetPort.java
index eab84c9..97985a5 100644
--- a/transition/ics/android/support/transition/TransitionSetPort.java
+++ b/transition/ics/android/support/transition/TransitionSetPort.java
@@ -232,21 +232,21 @@
 
     /** @hide */
     @Override
-    public void pause() {
-        super.pause();
+    public void pause(View sceneRoot) {
+        super.pause(sceneRoot);
         int numTransitions = mTransitions.size();
         for (int i = 0; i < numTransitions; ++i) {
-            mTransitions.get(i).pause();
+            mTransitions.get(i).pause(sceneRoot);
         }
     }
 
     /** @hide */
     @Override
-    public void resume() {
-        super.resume();
+    public void resume(View sceneRoot) {
+        super.resume(sceneRoot);
         int numTransitions = mTransitions.size();
         for (int i = 0; i < numTransitions; ++i) {
-            mTransitions.get(i).resume();
+            mTransitions.get(i).resume(sceneRoot);
         }
     }
 
diff --git a/transition/ics/android/support/transition/WindowIdPort.java b/transition/ics/android/support/transition/WindowIdPort.java
new file mode 100644
index 0000000..f768b2e
--- /dev/null
+++ b/transition/ics/android/support/transition/WindowIdPort.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import android.os.IBinder;
+import android.support.annotation.NonNull;
+import android.view.View;
+
+
+/**
+ * Backport of WindowId.
+ *
+ * <p>Since the use of WindowId in Transition API is limited to identifying windows, we can just
+ * wrap a window token and use it as an identifier.</p>
+ */
+class WindowIdPort {
+
+    private final IBinder mToken;
+
+    private WindowIdPort(IBinder token) {
+        mToken = token;
+    }
+
+    static WindowIdPort getWindowId(@NonNull View view) {
+        return new WindowIdPort(view.getWindowToken());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof WindowIdPort && ((WindowIdPort) obj).mToken.equals(this.mToken);
+    }
+
+}
diff --git a/transition/tests/src/android/support/transition/FadeTest.java b/transition/tests/src/android/support/transition/FadeTest.java
index f8760af..0ebd6cc 100644
--- a/transition/tests/src/android/support/transition/FadeTest.java
+++ b/transition/tests/src/android/support/transition/FadeTest.java
@@ -24,13 +24,14 @@
 import android.animation.Animator;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.view.ViewGroup;
 
 import org.junit.Before;
 import org.junit.Test;
 
-
+@MediumTest
 public class FadeTest extends BaseTest {
 
     private View mView;
diff --git a/transition/tests/src/android/support/transition/SceneTest.java b/transition/tests/src/android/support/transition/SceneTest.java
index 0ba0fb3..6333d59 100644
--- a/transition/tests/src/android/support/transition/SceneTest.java
+++ b/transition/tests/src/android/support/transition/SceneTest.java
@@ -20,6 +20,7 @@
 
 import android.support.test.annotation.UiThreadTest;
 import android.support.transition.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -28,6 +29,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.sameInstance;
 
+@MediumTest
 public class SceneTest extends BaseTest {
 
     @Test
diff --git a/transition/tests/src/android/support/transition/TransitionManagerTest.java b/transition/tests/src/android/support/transition/TransitionManagerTest.java
index a51450e..e07f333 100644
--- a/transition/tests/src/android/support/transition/TransitionManagerTest.java
+++ b/transition/tests/src/android/support/transition/TransitionManagerTest.java
@@ -24,6 +24,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
 import android.support.transition.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.ViewGroup;
 
 import org.junit.Before;
@@ -32,6 +33,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@MediumTest
 public class TransitionManagerTest extends BaseTest {
 
     private Scene[] mScenes = new Scene[2];
diff --git a/transition/tests/src/android/support/transition/TransitionTest.java b/transition/tests/src/android/support/transition/TransitionTest.java
index 9620837..1fe9474 100644
--- a/transition/tests/src/android/support/transition/TransitionTest.java
+++ b/transition/tests/src/android/support/transition/TransitionTest.java
@@ -26,6 +26,7 @@
 import android.animation.TimeInterpolator;
 import android.support.test.annotation.UiThreadTest;
 import android.support.transition.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -35,6 +36,7 @@
 
 import java.util.List;
 
+@MediumTest
 public class TransitionTest extends BaseTest {
 
     @Test
diff --git a/v13/Android.mk b/v13/Android.mk
index 6436768..e1e6062 100644
--- a/v13/Android.mk
+++ b/v13/Android.mk
@@ -52,6 +52,15 @@
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+# A helper sub-library that makes direct use of NYC MR-1 APIs.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v13-nyc-mr1
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, api25)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13-nyc
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
 # -----------------------------------------------------------------------
 
 include $(CLEAR_VARS)
@@ -61,7 +70,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 \
-        android-support-v13-nyc
+        android-support-v13-nyc-mr1
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java
new file mode 100644
index 0000000..e5d20a5
--- /dev/null
+++ b/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.os.Bundle;
+import android.view.inputmethod.EditorInfo;
+
+final class EditorInfoCompatApi25 {
+    public static void setContentMimeTypes(EditorInfo editorInfo, String[] contentMimeTypes) {
+        editorInfo.contentMimeTypes = contentMimeTypes;
+    }
+
+    public static String[] getContentMimeTypes(EditorInfo editorInfo) {
+        return editorInfo.contentMimeTypes;
+    }
+}
diff --git a/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java
new file mode 100644
index 0000000..a29bedd
--- /dev/null
+++ b/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.os.Bundle;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+import android.view.inputmethod.InputContentInfo;
+
+final class InputConnectionCompatApi25 {
+
+    public static boolean commitContent(InputConnection ic, Object inputContentInfo, int flags,
+            Bundle opts) {
+        return ic.commitContent((InputContentInfo)inputContentInfo, flags, opts);
+    }
+
+    public interface OnCommitContentListener {
+        boolean onCommitContent(Object inputContentInfo, int flags, Bundle opts);
+    }
+
+    public static InputConnection createWrapper(InputConnection ic,
+            final OnCommitContentListener onCommitContentListener) {
+        return new InputConnectionWrapper(ic, false /* mutable */) {
+            @Override
+            public boolean commitContent(InputContentInfo inputContentInfo, int flags,
+                        Bundle opts) {
+                if (onCommitContentListener.onCommitContent(inputContentInfo, flags, opts)) {
+                    return true;
+                }
+                return super.commitContent(inputContentInfo, flags, opts);
+            }
+        };
+    }
+
+}
diff --git a/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
new file mode 100644
index 0000000..c485ca6
--- /dev/null
+++ b/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Parcel;
+import android.view.inputmethod.InputContentInfo;
+
+final class InputContentInfoCompatApi25 {
+
+    public static Object create(Uri contentUri, ClipDescription description, Uri linkUri) {
+        return new InputContentInfo(contentUri, description, linkUri);
+    }
+
+    public static Uri getContentUri(Object inputContentInfo) {
+        return ((InputContentInfo) inputContentInfo).getContentUri();
+    }
+
+    public static ClipDescription getDescription(Object inputContentInfo) {
+        return ((InputContentInfo) inputContentInfo).getDescription();
+    }
+
+    public static Uri getLinkUri(Object inputContentInfo) {
+        return ((InputContentInfo) inputContentInfo).getLinkUri();
+    }
+
+    public static void requestPermission(Object inputContentInfo) {
+        ((InputContentInfo) inputContentInfo).requestPermission();
+    }
+
+    public static void releasePermission(Object inputContentInfo) {
+        ((InputContentInfo) inputContentInfo).requestPermission();
+    }
+}
diff --git a/v13/java/android/support/v13/app/ActivityCompat.java b/v13/java/android/support/v13/app/ActivityCompat.java
index e2a8a2c..8059a68 100644
--- a/v13/java/android/support/v13/app/ActivityCompat.java
+++ b/v13/java/android/support/v13/app/ActivityCompat.java
@@ -39,5 +39,7 @@
         return DragAndDropPermissionsCompat.request(activity, dragEvent);
     }
 
-    private ActivityCompat() {}
+    protected ActivityCompat() {
+        // Not publicly instantiable, but may be extended.
+    }
 }
diff --git a/v13/java/android/support/v13/app/FragmentTabHost.java b/v13/java/android/support/v13/app/FragmentTabHost.java
index c010b4f..6cfd0ad 100644
--- a/v13/java/android/support/v13/app/FragmentTabHost.java
+++ b/v13/java/android/support/v13/app/FragmentTabHost.java
@@ -51,10 +51,10 @@
     private boolean mAttached;
 
     static final class TabInfo {
-        private final String tag;
-        private final Class<?> clss;
-        private final Bundle args;
-        private Fragment fragment;
+        final String tag;
+        final Class<?> clss;
+        final Bundle args;
+        Fragment fragment;
 
         TabInfo(String _tag, Class<?> _class, Bundle _args) {
             tag = _tag;
@@ -86,7 +86,7 @@
             super(superState);
         }
 
-        private SavedState(Parcel in) {
+        SavedState(Parcel in) {
             super(in);
             curTab = in.readString();
         }
diff --git a/v13/java/android/support/v13/view/ViewCompat.java b/v13/java/android/support/v13/view/ViewCompat.java
index 38db5fa..971d70d 100644
--- a/v13/java/android/support/v13/view/ViewCompat.java
+++ b/v13/java/android/support/v13/view/ViewCompat.java
@@ -33,6 +33,9 @@
     }
 
     private static class BaseViewCompatImpl implements ViewCompatImpl {
+        BaseViewCompatImpl() {
+        }
+
         @Override
         public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
                 Object localState, int flags) {
@@ -51,6 +54,9 @@
     }
 
     private static class Api24ViewCompatImpl implements ViewCompatImpl {
+        Api24ViewCompatImpl() {
+        }
+
         @Override
         public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
                 Object localState, int flags) {
diff --git a/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java b/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
new file mode 100644
index 0000000..c1bffd4
--- /dev/null
+++ b/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+public final class EditorInfoCompat {
+
+    private interface EditorInfoCompatImpl {
+        void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+                @Nullable String[] contentMimeTypes);
+        @NonNull
+        String[] getContentMimeTypes(@NonNull EditorInfo editorInfo);
+    }
+
+    private final static String[] EMPTY_STRING_ARRAY = new String[0];
+
+    private final static class BaseEditorInfoCompatImpl implements EditorInfoCompatImpl {
+        private static String CONTENT_MIME_TYPES_KEY =
+                "android.support.v13.view.inputmethod.EditorInfoCompat.CONTENT_MIME_TYPES";
+
+        @Override
+        public void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+                @Nullable String[] contentMimeTypes) {
+            if (editorInfo.extras == null) {
+                editorInfo.extras = new Bundle();
+            }
+            editorInfo.extras.putStringArray(CONTENT_MIME_TYPES_KEY, contentMimeTypes);
+        }
+
+        @NonNull
+        @Override
+        public String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
+            if (editorInfo.extras == null) {
+                return EMPTY_STRING_ARRAY;
+            }
+            String[] result = editorInfo.extras.getStringArray(CONTENT_MIME_TYPES_KEY);
+            return result != null ? result : EMPTY_STRING_ARRAY;
+        }
+    }
+
+    private final static class Api25EditorInfoCompatImpl implements EditorInfoCompatImpl {
+        @Override
+        public void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+                @Nullable String[] contentMimeTypes) {
+            EditorInfoCompatApi25.setContentMimeTypes(editorInfo, contentMimeTypes);
+        }
+
+        @NonNull
+        @Override
+        public String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
+            String[] result = EditorInfoCompatApi25.getContentMimeTypes(editorInfo);
+            return result != null ? result : EMPTY_STRING_ARRAY;
+        }
+    }
+
+    private static final EditorInfoCompatImpl IMPL;
+    static {
+        if (BuildCompat.isAtLeastNMR1()) {
+            IMPL = new Api25EditorInfoCompatImpl();
+        } else {
+            IMPL = new BaseEditorInfoCompatImpl();
+        }
+    }
+
+    /**
+     * Sets MIME types that can be accepted by the target editor if the IME calls
+     * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+     * InputContentInfoCompat, int, Bundle)}.
+     *
+     * @param editorInfo the editor with which we associate supported MIME types
+     * @param contentMimeTypes an array of MIME types. {@code null} and an empty array means that
+     *                         {@link InputConnectionCompat#commitContent(
+     *                         InputConnection, EditorInfo, InputContentInfoCompat, int, Bundle)
+     *                         is not supported on this Editor
+     */
+    public static void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+            @Nullable String[] contentMimeTypes) {
+        IMPL.setContentMimeTypes(editorInfo, contentMimeTypes);
+    }
+
+    /**
+     * Gets MIME types that can be accepted by the target editor if the IME calls
+     * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+     * InputContentInfoCompat, int, Bundle)}
+     *
+     * @param editorInfo the editor from which we get the MIME types
+     * @return an array of MIME types. An empty array means that {@link
+     * InputConnectionCompat#commitContent(InputConnection, EditorInfo, InputContentInfoCompat,
+     * int, Bundle)} is not supported on this editor
+     */
+    @NonNull
+    public static String[] getContentMimeTypes(EditorInfo editorInfo) {
+        return IMPL.getContentMimeTypes(editorInfo);
+    }
+
+}
diff --git a/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java b/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
new file mode 100644
index 0000000..b740502
--- /dev/null
+++ b/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
@@ -0,0 +1,281 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+
+/**
+ * Helper for accessing features in {@link InputConnection} introduced after API level 13 in a
+ * backwards compatible fashion.
+ */
+public final class InputConnectionCompat {
+
+    private interface InputConnectionCompatImpl {
+        boolean commitContent(@NonNull InputConnection inputConnection,
+                @NonNull InputContentInfoCompat inputContentInfo, int flags, @Nullable Bundle opts);
+
+        @NonNull
+        InputConnection createWrapper(@NonNull InputConnection ic,
+                @NonNull EditorInfo editorInfo, @NonNull OnCommitContentListener callback);
+    }
+
+    static final class BaseInputContentInfoCompatImpl implements InputConnectionCompatImpl {
+
+        private static String COMMIT_CONTENT_ACTION =
+                "android.support.v13.view.inputmethod.InputConnectionCompat.COMMIT_CONTENT";
+        private static String COMMIT_CONTENT_CONTENT_URI_KEY =
+                "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_URI";
+        private static String COMMIT_CONTENT_DESCRIPTION_KEY =
+                "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_DESCRIPTION";
+        private static String COMMIT_CONTENT_LINK_URI_KEY =
+                "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_LINK_URI";
+        private static String COMMIT_CONTENT_OPTS_KEY =
+                "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_OPTS";
+        private static String COMMIT_CONTENT_FLAGS_KEY =
+                "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_FLAGS";
+        private static String COMMIT_CONTENT_RESULT_RECEIVER =
+                "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_RESULT_RECEIVER";
+
+        @Override
+        public boolean commitContent(@NonNull InputConnection inputConnection,
+                @NonNull InputContentInfoCompat inputContentInfo, int flags,
+                @Nullable Bundle opts) {
+            final Bundle params = new Bundle();
+            params.putParcelable(COMMIT_CONTENT_CONTENT_URI_KEY, inputContentInfo.getContentUri());
+            params.putParcelable(COMMIT_CONTENT_DESCRIPTION_KEY, inputContentInfo.getDescription());
+            params.putParcelable(COMMIT_CONTENT_LINK_URI_KEY, inputContentInfo.getLinkUri());
+            params.putInt(COMMIT_CONTENT_FLAGS_KEY, flags);
+            params.putParcelable(COMMIT_CONTENT_OPTS_KEY, opts);
+            // TODO: Support COMMIT_CONTENT_RESULT_RECEIVER.
+            return inputConnection.performPrivateCommand(COMMIT_CONTENT_ACTION, params);
+        }
+
+        @NonNull
+        @Override
+        public InputConnection createWrapper(@NonNull InputConnection ic,
+                @NonNull EditorInfo editorInfo,
+                @NonNull OnCommitContentListener onCommitContentListener) {
+            String[] contentMimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);
+            if (contentMimeTypes.length == 0) {
+                return ic;
+            }
+            final OnCommitContentListener listener = onCommitContentListener;
+            return new InputConnectionWrapper(ic, false /* mutable */) {
+                @Override
+                public boolean performPrivateCommand(String action, Bundle data) {
+                    if (BaseInputContentInfoCompatImpl.handlePerformPrivateCommand(action, data,
+                            listener)) {
+                        return true;
+                    }
+                    return super.performPrivateCommand(action, data);
+                }
+            };
+        }
+
+        static boolean handlePerformPrivateCommand(
+                @Nullable String action,
+                @NonNull Bundle data,
+                @NonNull OnCommitContentListener onCommitContentListener) {
+            if (!TextUtils.equals(COMMIT_CONTENT_ACTION, action)) {
+                return false;
+            }
+            if (data == null) {
+                return false;
+            }
+            ResultReceiver resultReceiver = null;
+            boolean result = false;
+            try {
+                resultReceiver = data.getParcelable(COMMIT_CONTENT_RESULT_RECEIVER);
+                final Uri contentUri = data.getParcelable(COMMIT_CONTENT_CONTENT_URI_KEY);
+                final ClipDescription description = data.getParcelable(
+                        COMMIT_CONTENT_DESCRIPTION_KEY);
+                final Uri linkUri = data.getParcelable(COMMIT_CONTENT_LINK_URI_KEY);
+                final int flags = data.getInt(COMMIT_CONTENT_FLAGS_KEY);
+                final Bundle opts = data.getParcelable(COMMIT_CONTENT_OPTS_KEY);
+                final InputContentInfoCompat inputContentInfo =
+                        new InputContentInfoCompat(contentUri, description, linkUri);
+                result = onCommitContentListener.onCommitContent(inputContentInfo, flags, opts);
+            } finally {
+                if (resultReceiver != null) {
+                    resultReceiver.send(result ? 1 : 0, null);
+                }
+            }
+            return result;
+        }
+    }
+
+    private final static class Api25InputContentInfoCompatImpl
+            implements InputConnectionCompatImpl {
+        @Override
+        public boolean commitContent(@NonNull InputConnection inputConnection,
+                @NonNull InputContentInfoCompat inputContentInfo, int flags,
+                @Nullable Bundle opts) {
+            return InputConnectionCompatApi25.commitContent(inputConnection,
+                    inputContentInfo.unwrap(), flags, opts);
+        }
+
+        @Nullable
+        @Override
+        public InputConnection createWrapper(
+                @Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo,
+                @Nullable OnCommitContentListener onCommitContentListener) {
+            final OnCommitContentListener listener = onCommitContentListener;
+            return InputConnectionCompatApi25.createWrapper(
+                    inputConnection,
+                    new InputConnectionCompatApi25.OnCommitContentListener() {
+                        @Override
+                        public boolean onCommitContent(Object inputContentInfo, int flags,
+                                Bundle opts) {
+                            InputContentInfoCompat inputContentInfoCompat =
+                                    InputContentInfoCompat.wrap(inputContentInfo);
+                            return listener.onCommitContent(inputContentInfoCompat, flags, opts);
+                        }
+            });
+        }
+    }
+
+    private static final InputConnectionCompatImpl IMPL;
+    static {
+        if (BuildCompat.isAtLeastNMR1()) {
+            IMPL = new Api25InputContentInfoCompatImpl();
+        } else {
+            IMPL = new BaseInputContentInfoCompatImpl();
+        }
+    }
+
+    /**
+     * Calls commitContent API, in a backwards compatible fashion.
+     *
+     * @param inputConnection {@link InputConnection} with which commitContent API will be called
+     * @param editorInfo {@link EditorInfo} associated with the given {@code inputConnection}
+     * @param inputContentInfo content information to be passed to the editor
+     * @param flags {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}
+     * @param opts optional bundle data. This can be {@code null}
+     * @return {@code true} if this request is accepted by the application, no matter if the request
+     * is already handled or still being handled in background
+     */
+    public static boolean commitContent(@NonNull InputConnection inputConnection,
+            @NonNull EditorInfo editorInfo, @NonNull InputContentInfoCompat inputContentInfo,
+            int flags, @Nullable Bundle opts) {
+        final ClipDescription description = inputContentInfo.getDescription();
+        boolean supported = false;
+        for (String mimeType : EditorInfoCompat.getContentMimeTypes(editorInfo)) {
+            if (description.hasMimeType(mimeType)) {
+                supported = true;
+                break;
+            }
+        }
+        if (!supported) {
+            return false;
+        }
+
+        return IMPL.commitContent(inputConnection, inputContentInfo, flags, opts);
+    }
+
+    /**
+     * When this flag is used, the editor will be able to request temporary access permissions to
+     * the content URI contained in the {@link InputContentInfoCompat} object, in a similar manner
+     * that has been recommended in
+     * <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.
+     *
+     * <p>Make sure that the content provider owning the Uri sets the
+     * {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
+     * grantUriPermissions} attribute in its manifest or included the
+     * {@link android.R.styleable#AndroidManifestGrantUriPermission
+     * &lt;grant-uri-permissions&gt;} tag.</p>
+     *
+     * <p>Supported only on API &gt;= 25.</p>
+     *
+     * <p>On API &lt;= 24 devices, IME developers need to ensure that the content URI is accessible
+     * only from the target application, for example, by generating a URL with a unique name that
+     * others cannot guess. IME developers can also rely on the following information of the target
+     * application to do additional access checks in their {@link android.content.ContentProvider}.
+     * </p>
+     * <ul>
+     *     <li>On API &gt;= 23 {@link EditorInfo#packageName} is guaranteed to not be spoofed, which
+     *     can later be compared with {@link android.content.ContentProvider#getCallingPackage()} in
+     *     the {@link android.content.ContentProvider}.
+     *     </li>
+     *     <li>{@link android.view.inputmethod.InputBinding#getUid()} is guaranteed to not be
+     *     spoofed, which can later be compared with {@link android.os.Binder#getCallingUid()} in
+     *     the {@link android.content.ContentProvider}.</li>
+     * </ul>
+     */
+    public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 0x00000001;
+
+    /**
+     * Listener for commitContent method call, in a backwards compatible fashion.
+     */
+    public interface OnCommitContentListener {
+        /**
+         * Intercepts InputConnection#commitContent API calls.
+         *
+         * @param inputContentInfo content to be committed
+         * @param flags {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}
+         * @param opts optional bundle data. This can be {@code null}
+         * @return {@code true} if this request is accepted by the application, no matter if the
+         * request is already handled or still being handled in background. {@code false} to use the
+         * default implementation
+         */
+        boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts);
+    }
+
+    /**
+     * Creates a wrapper {@link InputConnection} object from an existing {@link InputConnection}
+     * and {@link OnCommitContentListener} that can be returned to the system.
+     *
+     * <p>By returning the wrapper object to the IME, the editor can be notified by
+     * {@link OnCommitContentListener#onCommitContent(InputContentInfoCompat, int, Bundle)}
+     * when the IME calls
+     * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+     * InputContentInfoCompat, int, Bundle)} and the corresponding Framework API that is available
+     * on API &gt;= 25.</p>
+     *
+     * @param inputConnection {@link InputConnection} to be wrapped
+     * @param editorInfo {@link EditorInfo} associated with the given {@code inputConnection}
+     * @param onCommitContentListener the listener that the wrapper object will call
+     * @return a wrapper {@link InputConnection} object that can be returned to the IME
+     * @throws IllegalArgumentException when {@code inputConnection}, {@code editorInfo}, or
+     * {@code onCommitContentListener} is {@code null}
+     */
+    @NonNull
+    public static InputConnection createWrapper(@NonNull InputConnection inputConnection,
+            @NonNull EditorInfo editorInfo,
+            @NonNull OnCommitContentListener onCommitContentListener) {
+        if (inputConnection == null) {
+            throw new IllegalArgumentException("inputConnection must be non-null");
+        }
+        if (editorInfo == null) {
+            throw new IllegalArgumentException("editorInfo must be non-null");
+        }
+        if (onCommitContentListener == null) {
+            throw new IllegalArgumentException("onCommitContentListener must be non-null");
+        }
+        return IMPL.createWrapper(inputConnection, editorInfo, onCommitContentListener);
+    }
+
+}
diff --git a/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java b/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java
new file mode 100644
index 0000000..6f20594
--- /dev/null
+++ b/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java
@@ -0,0 +1,237 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+
+public final class InputContentInfoCompat {
+
+    private interface InputContentInfoCompatImpl {
+        @NonNull
+        Uri getContentUri();
+
+        @NonNull
+        ClipDescription getDescription();
+
+        @Nullable
+        Uri getLinkUri();
+
+        @Nullable
+        Object getInputContentInfo();
+
+        void requestPermission();
+
+        void releasePermission();
+    }
+
+    private final static class BaseInputContentInfoCompatImpl
+            implements InputContentInfoCompatImpl {
+        @NonNull
+        private final Uri mContentUri;
+        @NonNull
+        private final ClipDescription mDescription;
+        @Nullable
+        private final Uri mLinkUri;
+
+        public BaseInputContentInfoCompatImpl(@NonNull Uri contentUri,
+                @NonNull ClipDescription description, @Nullable Uri linkUri) {
+            mContentUri = contentUri;
+            mDescription = description;
+            mLinkUri = linkUri;
+        }
+
+        @NonNull
+        @Override
+        public Uri getContentUri() {
+            return mContentUri;
+        }
+
+        @NonNull
+        @Override
+        public ClipDescription getDescription() {
+            return mDescription;
+        }
+
+        @Nullable
+        @Override
+        public Uri getLinkUri() {
+            return mLinkUri;
+        }
+
+        @Nullable
+        @Override
+        public Object getInputContentInfo() {
+            return null;
+        }
+
+        @Override
+        public void requestPermission() {
+            return;
+        }
+
+        @Override
+        public void releasePermission() {
+            return;
+        }
+    }
+
+    private final static class Api25InputContentInfoCompatImpl
+            implements InputContentInfoCompatImpl {
+        @NonNull
+        final Object mObject;
+
+        public Api25InputContentInfoCompatImpl(@NonNull Object inputContentInfo) {
+            mObject = inputContentInfo;
+        }
+
+        public Api25InputContentInfoCompatImpl(@NonNull Uri contentUri,
+                @NonNull ClipDescription description, @Nullable Uri linkUri) {
+            mObject = InputContentInfoCompatApi25.create(contentUri, description, linkUri);
+        }
+
+        @Override
+        @NonNull
+        public Uri getContentUri() {
+            return InputContentInfoCompatApi25.getContentUri(mObject);
+        }
+
+        @Override
+        @NonNull
+        public ClipDescription getDescription() {
+            return InputContentInfoCompatApi25.getDescription(mObject);
+        }
+
+        @Override
+        @Nullable
+        public Uri getLinkUri() {
+            return InputContentInfoCompatApi25.getLinkUri(mObject);
+        }
+
+        @Override
+        @Nullable
+        public Object getInputContentInfo() {
+            return mObject;
+        }
+
+        @Override
+        public void requestPermission() {
+            InputContentInfoCompatApi25.requestPermission(mObject);
+        }
+
+        @Override
+        public void releasePermission() {
+            InputContentInfoCompatApi25.releasePermission(mObject);
+        }
+    }
+
+    private final InputContentInfoCompatImpl mImpl;
+
+    public InputContentInfoCompat(@NonNull Uri contentUri,
+            @NonNull ClipDescription description, @Nullable Uri linkUri) {
+        if (BuildCompat.isAtLeastNMR1()) {
+            mImpl = new Api25InputContentInfoCompatImpl(contentUri, description, linkUri);
+        } else {
+            mImpl = new BaseInputContentInfoCompatImpl(contentUri, description, linkUri);
+        }
+    }
+
+    private InputContentInfoCompat(@NonNull InputContentInfoCompatImpl impl) {
+        mImpl = impl;
+    }
+
+    /**
+     * @return content URI with which the content can be obtained.
+     */
+    @NonNull
+    public Uri getContentUri() {
+        return mImpl.getContentUri();
+    }
+
+    /**
+     * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
+     * such as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility
+     * purpose.
+     */
+    @NonNull
+    public ClipDescription getDescription() {
+        return mImpl.getDescription();
+    }
+
+    /**
+     * @return an optional {@code http} or {@code https} URI that is related to this content.
+     */
+    @Nullable
+    public Uri getLinkUri() {
+        return mImpl.getLinkUri();
+    }
+
+    /**
+     * Creates an instance from a framework android.view.inputmethod.InputContentInfo object.
+     *
+     * <p>This method always returns {@code null} on API &lt;= 24.</p>
+     *
+     * @param inputContentInfo an android.view.inputmethod.InputContentInfo object, or {@code null}
+     *                         if none.
+     * @return an equivalent {@link InputContentInfoCompat} object, or {@code null} if not
+     * supported.
+     */
+    @Nullable
+    public static InputContentInfoCompat wrap(@Nullable Object inputContentInfo) {
+        if (inputContentInfo == null) {
+            return null;
+        }
+        if (!BuildCompat.isAtLeastNMR1()) {
+            return null;
+        }
+        return new InputContentInfoCompat(new Api25InputContentInfoCompatImpl(inputContentInfo));
+    }
+
+    /**
+     * Gets the underlying framework android.view.inputmethod.InputContentInfo object.
+     *
+     * <p>This method always returns {@code null} on API &lt;= 24.</p>
+     *
+     * @return an equivalent android.view.inputmethod.InputContentInfo object, or {@code null} if
+     * not supported.
+     */
+    @Nullable
+    public Object unwrap() {
+        return mImpl.getInputContentInfo();
+    }
+
+    /**
+     * Requests a temporary read-only access permission for content URI associated with this object.
+     *
+     * <p>Does nothing if the temporary permission is already granted.</p>
+     */
+    public void requestPermission() {
+        mImpl.requestPermission();
+    }
+
+    /**
+     * Releases a temporary read-only access permission for content URI associated with this object.
+     *
+     * <p>Does nothing if the temporary permission is not granted.</p>
+     */
+    public void releasePermission() {
+        mImpl.releasePermission();
+    }
+}
diff --git a/v17/leanback/res/values-bs-rBA/strings.xml b/v17/leanback/res/values-bs-rBA/strings.xml
index cdfe434..63a76e2 100644
--- a/v17/leanback/res/values-bs-rBA/strings.xml
+++ b/v17/leanback/res/values-bs-rBA/strings.xml
@@ -53,5 +53,5 @@
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
     <string name="lb_time_separator" msgid="2763247350845477227">":"</string>
     <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAPOČNITE"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Sljedeća"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Naprijed"</string>
 </resources>
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
index 6f76c0e..40040bb 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
@@ -48,7 +48,7 @@
             final boolean isRtl = ViewCompat.getLayoutDirection(focused) ==
                     View.LAYOUT_DIRECTION_RTL;
             final int forward = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
-            if (mTitleView.hasFocus() && direction == View.FOCUS_DOWN || direction == forward) {
+            if (mTitleView.hasFocus() && (direction == View.FOCUS_DOWN || direction == forward)) {
                 return mSceneRoot;
             }
             return null;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
index b369b19..afeb175 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
@@ -16,6 +16,7 @@
 package android.support.v17.leanback.app;
 
 import android.support.v17.leanback.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 
 import android.support.v17.leanback.widget.Presenter;
@@ -42,6 +43,7 @@
 /**
  * @hide from javadoc
  */
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class BrowseFragmentTest {
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
index ebfed89..bab554d 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
@@ -18,6 +18,7 @@
 package android.support.v17.leanback.app;
 
 import android.support.v17.leanback.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 
 import android.support.v17.leanback.widget.Presenter;
@@ -44,6 +45,7 @@
 /**
  * @hide from javadoc
  */
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class BrowseSupportFragmentTest {
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
index 72f4f44..9cab5a1 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
@@ -25,6 +25,7 @@
 import android.support.v17.leanback.widget.VerticalGridView;
 import android.support.v17.leanback.widget.picker.DatePicker;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
@@ -37,6 +38,7 @@
 import java.util.Date;
 import java.util.List;
 
+@MediumTest
 public class GuidedDatePickerTest extends
         ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity> {
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
index 72391d1..8387dbd 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
@@ -22,6 +22,7 @@
 import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidedAction;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 import android.view.KeyEvent;
 
@@ -30,9 +31,9 @@
 import java.util.Collections;
 import java.util.List;
 
+@MediumTest
 public class GuidedStepAttributesTest extends
-        ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity>
-{
+        ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity> {
     static final long TRANSITION_LENGTH = 1000;
 
     static final String TAG = "GuidedStepAttributesTest";
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
index 5fbcb0e..e1739ff 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -27,6 +27,7 @@
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.text.Selection;
 import android.text.Spannable;
 import android.util.SparseArray;
@@ -44,6 +45,7 @@
 /**
  * @hide from javadoc
  */
+@MediumTest
 public class GridWidgetTest extends ActivityInstrumentationTestCase2<GridActivity> {
 
     private static final boolean HUMAN_DELAY = false;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
index ba5ddda..b9a230a 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
@@ -19,6 +19,7 @@
 import android.support.v17.leanback.app.HeadersFragment;
 import android.support.v17.leanback.R;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.ContextThemeWrapper;
 import android.widget.FrameLayout;
 import android.view.View;
@@ -28,6 +29,7 @@
 import android.support.v17.leanback.widget.DividerPresenter;
 import android.view.ContextThemeWrapper;
 
+@MediumTest
 public class PresenterTest extends AndroidTestCase {
 
     public void testZoomFactors() throws Throwable {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
index e7ec4bf..3b99486 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
@@ -16,12 +16,13 @@
 package android.support.v17.leanback.widget;
 
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-
+@MediumTest
 public class ShadowOverlayContainerTest extends AndroidTestCase {
 
     public void testWrapContent() {
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_low_normal.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_low_normal.9.png
new file mode 100644
index 0000000..af91f5e
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_low_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_low_pressed.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_low_pressed.9.png
new file mode 100644
index 0000000..1602ab8
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_normal.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_normal.9.png
new file mode 100644
index 0000000..6ebed8b
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_normal_pressed.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_normal_pressed.9.png
new file mode 100644
index 0000000..6193822
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/v7/appcompat/res/drawable-hdpi/notify_panel_notification_icon_bg.png
new file mode 100644
index 0000000..6f37a22
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_low_normal.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_low_normal.9.png
new file mode 100644
index 0000000..62de9d7
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_low_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_low_pressed.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_low_pressed.9.png
new file mode 100644
index 0000000..eaabd93
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_normal.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_normal.9.png
new file mode 100644
index 0000000..aa239b3
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_normal_pressed.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_normal_pressed.9.png
new file mode 100644
index 0000000..62d8622
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/v7/appcompat/res/drawable-mdpi/notify_panel_notification_icon_bg.png
new file mode 100644
index 0000000..c286875
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-v21/notification_action_background.xml b/v7/appcompat/res/drawable-v21/notification_action_background.xml
new file mode 100644
index 0000000..852c3f0
--- /dev/null
+++ b/v7/appcompat/res/drawable-v21/notification_action_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/ripple_material_light">
+    <item android:id="@android:id/mask"
+        android:drawable="@drawable/abc_btn_default_mtrl_shape" />
+</ripple>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_low_normal.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_normal.9.png
new file mode 100644
index 0000000..8c884de
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_low_pressed.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_pressed.9.png
new file mode 100644
index 0000000..32e00be
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_normal.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal.9.png
new file mode 100644
index 0000000..bdf477b
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_normal_pressed.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal_pressed.9.png
new file mode 100644
index 0000000..5c4da74
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notify_panel_notification_icon_bg.png b/v7/appcompat/res/drawable-xhdpi/notify_panel_notification_icon_bg.png
new file mode 100644
index 0000000..9128e62
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/v7/appcompat/res/drawable/notification_bg.xml b/v7/appcompat/res/drawable/notification_bg.xml
new file mode 100644
index 0000000..1232b4c
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+    <item android:state_pressed="true"
+        android:drawable="@drawable/notification_bg_normal_pressed" />
+    <item android:state_pressed="false" android:drawable="@drawable/notification_bg_normal" />
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/notification_bg_low.xml b/v7/appcompat/res/drawable/notification_bg_low.xml
new file mode 100644
index 0000000..72e58ae
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_bg_low.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+    <item android:state_pressed="true"  android:drawable="@drawable/notification_bg_low_pressed" />
+    <item android:state_pressed="false" android:drawable="@drawable/notification_bg_low_normal" />
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/notification_icon_background.xml b/v7/appcompat/res/drawable/notification_icon_background.xml
new file mode 100644
index 0000000..490a797
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_icon_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid
+        android:color="@color/notification_icon_bg_color"/>
+</shape>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/notification_tile_bg.xml b/v7/appcompat/res/drawable/notification_tile_bg.xml
new file mode 100644
index 0000000..8eee7ef
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_tile_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<bitmap
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:tileMode="repeat"
+    android:src="@drawable/notify_panel_notification_icon_bg"
+/>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v16/notification_template_custom_big.xml b/v7/appcompat/res/layout-v16/notification_template_custom_big.xml
new file mode 100644
index 0000000..24c3323
--- /dev/null
+++ b/v7/appcompat/res/layout-v16/notification_template_custom_big.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/notification_background"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+        android:scaleType="center"
+    />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:orientation="vertical" >
+        <LinearLayout
+            android:id="@+id/notification_main_column_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/notification_large_icon_width"
+            android:layout_marginStart="@dimen/notification_large_icon_width"
+            android:paddingTop="@dimen/notification_main_column_padding_top"
+            android:minHeight="@dimen/notification_large_icon_height"
+            android:orientation="horizontal">
+            <FrameLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginLeft="@dimen/notification_content_margin_start"
+                android:layout_marginStart="@dimen/notification_content_margin_start"
+                android:layout_marginBottom="8dp"
+                android:layout_marginRight="8dp"
+                android:layout_marginEnd="8dp" />
+            <FrameLayout
+                android:id="@+id/right_side"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="8dp"
+                android:layout_marginEnd="8dp"
+                android:paddingTop="@dimen/notification_right_side_padding_top">
+                <ViewStub android:id="@+id/time"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="end|top"
+                    android:visibility="gone"
+                    android:layout="@layout/notification_template_part_time" />
+                <ViewStub android:id="@+id/chronometer"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="end|top"
+                    android:visibility="gone"
+                    android:layout="@layout/notification_template_part_chronometer" />
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_gravity="end|bottom"
+                    android:layout_marginTop="20dp">
+                    <TextView android:id="@+id/info"
+                        android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:singleLine="true"
+                    />
+                    <ImageView android:id="@+id/right_icon"
+                        android:layout_width="16dp"
+                        android:layout_height="16dp"
+                        android:layout_gravity="center"
+                        android:layout_marginLeft="8dp"
+                        android:layout_marginStart="8dp"
+                        android:scaleType="centerInside"
+                        android:visibility="gone"
+                        android:alpha="0.6"
+                    />
+                </LinearLayout>
+            </FrameLayout>
+        </LinearLayout>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="1px"
+            android:id="@+id/action_divider"
+            android:visibility="gone"
+            android:layout_marginLeft="@dimen/notification_large_icon_width"
+            android:layout_marginStart="@dimen/notification_large_icon_width"
+            android:background="?android:attr/dividerHorizontal" />
+        <LinearLayout
+            android:id="@+id/actions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:visibility="gone"
+            android:showDividers="middle"
+            android:divider="?android:attr/listDivider"
+            android:dividerPadding="12dp"
+            android:layout_marginLeft="@dimen/notification_large_icon_width"
+            android:layout_marginStart="@dimen/notification_large_icon_width" >
+            <!-- actions will be added here -->
+        </LinearLayout>
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_action.xml b/v7/appcompat/res/layout-v21/notification_action.xml
new file mode 100644
index 0000000..c60bf7d
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_action.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/Widget.AppCompat.NotificationActionContainer"
+    android:id="@+id/action_container"
+    android:layout_width="0dp"
+    android:layout_weight="1"
+    android:layout_height="48dp"
+    android:paddingStart="4dp"
+    android:orientation="horizontal">
+    <ImageView
+        android:id="@+id/action_image"
+        android:layout_width="@dimen/notification_action_icon_size"
+        android:layout_height="@dimen/notification_action_icon_size"
+        android:layout_gravity="center|start"
+        android:scaleType="centerInside"/>
+    <TextView
+        style="@style/Widget.AppCompat.NotificationActionText"
+        android:id="@+id/action_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center|start"
+        android:paddingStart="4dp"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:clickable="false"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_action_tombstone.xml b/v7/appcompat/res/layout-v21/notification_action_tombstone.xml
new file mode 100644
index 0000000..1637c6f
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_action_tombstone.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/Widget.AppCompat.NotificationActionContainer"
+    android:id="@+id/action_container"
+    android:layout_width="0dp"
+    android:layout_weight="1"
+    android:layout_height="48dp"
+    android:paddingStart="4dp"
+    android:orientation="horizontal"
+    android:enabled="false"
+    android:background="@null">
+    <ImageView
+        android:id="@+id/action_image"
+        android:layout_width="@dimen/notification_action_icon_size"
+        android:layout_height="@dimen/notification_action_icon_size"
+        android:layout_gravity="center|start"
+        android:scaleType="centerInside"
+        android:enabled="false"
+        android:alpha="0.5"/>
+    <TextView
+        style="@style/Widget.AppCompat.NotificationActionText"
+        android:id="@+id/action_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center|start"
+        android:paddingStart="4dp"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:clickable="false"
+        android:enabled="false"
+        android:alpha="0.5"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_template_custom_big.xml b/v7/appcompat/res/layout-v21/notification_template_custom_big.xml
new file mode 100644
index 0000000..38332bd
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_template_custom_big.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/notification_background"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" >
+    <include layout="@layout/notification_template_icon_group"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+    />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:layout_marginStart="@dimen/notification_large_icon_width"
+        android:orientation="vertical" >
+        <LinearLayout
+            android:id="@+id/notification_main_column_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:minHeight="@dimen/notification_large_icon_height"
+            android:orientation="horizontal">
+            <FrameLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginEnd="8dp"
+                android:layout_marginBottom="8dp"/>
+            <FrameLayout
+                android:id="@+id/right_side"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="8dp"
+                android:paddingTop="@dimen/notification_right_side_padding_top">
+                <ViewStub android:id="@+id/time"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="end|top"
+                    android:visibility="gone"
+                    android:layout="@layout/notification_template_part_time" />
+                <ViewStub android:id="@+id/chronometer"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="end|top"
+                    android:visibility="gone"
+                    android:layout="@layout/notification_template_part_chronometer" />
+                <TextView android:id="@+id/info"
+                    android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="20dp"
+                    android:layout_gravity="end|bottom"
+                    android:singleLine="true"
+                />
+            </FrameLayout>
+        </LinearLayout>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:id="@+id/action_divider"
+            android:visibility="gone"
+            android:background="#29000000" />
+        <LinearLayout
+            android:id="@+id/actions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="-8dp"
+            android:orientation="horizontal"
+            android:visibility="gone"
+        >
+            <!-- actions will be added here -->
+        </LinearLayout>
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_template_icon_group.xml b/v7/appcompat/res/layout-v21/notification_template_icon_group.xml
new file mode 100644
index 0000000..6c19022
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_template_icon_group.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/notification_large_icon_width"
+    android:layout_height="@dimen/notification_large_icon_height"
+    android:id="@+id/icon_group"
+>
+    <ImageView android:id="@+id/icon"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/notification_big_circle_margin"
+        android:layout_marginBottom="@dimen/notification_big_circle_margin"
+        android:layout_marginStart="@dimen/notification_big_circle_margin"
+        android:layout_marginEnd="@dimen/notification_big_circle_margin"
+        android:scaleType="centerInside"
+    />
+    <ImageView android:id="@+id/right_icon"
+        android:layout_width="@dimen/notification_right_icon_size"
+        android:layout_height="@dimen/notification_right_icon_size"
+        android:layout_gravity="end|bottom"
+        android:scaleType="centerInside"
+        android:visibility="gone"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="8dp"
+    />
+</FrameLayout>
+
diff --git a/v7/appcompat/res/layout/notification_action.xml b/v7/appcompat/res/layout/notification_action.xml
new file mode 100644
index 0000000..82e95a5
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_action.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/Widget.AppCompat.NotificationActionContainer"
+    android:id="@+id/action_container"
+    android:layout_width="0dp"
+    android:layout_weight="1"
+    android:layout_height="48dp"
+    android:paddingLeft="4dp"
+    android:paddingStart="4dp"
+    android:orientation="horizontal">
+    <ImageView
+        android:id="@+id/action_image"
+        android:layout_width="@dimen/notification_action_icon_size"
+        android:layout_height="@dimen/notification_action_icon_size"
+        android:layout_gravity="center|start"
+        android:scaleType="centerInside"/>
+    <TextView
+        style="@style/Widget.AppCompat.NotificationActionText"
+        android:id="@+id/action_text"
+        android:textColor="#ccc"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center|start"
+        android:paddingLeft="4dp"
+        android:paddingStart="4dp"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:clickable="false"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/notification_action_tombstone.xml b/v7/appcompat/res/layout/notification_action_tombstone.xml
new file mode 100644
index 0000000..d491c78
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_action_tombstone.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/Widget.AppCompat.NotificationActionContainer"
+    android:id="@+id/action_container"
+    android:layout_width="0dp"
+    android:layout_weight="1"
+    android:layout_height="48dp"
+    android:paddingLeft="4dp"
+    android:paddingStart="4dp"
+    android:orientation="horizontal"
+    android:enabled="false"
+    android:background="@null">
+    <ImageView
+        android:id="@+id/action_image"
+        android:layout_width="@dimen/notification_action_icon_size"
+        android:layout_height="@dimen/notification_action_icon_size"
+        android:layout_gravity="center|start"
+        android:scaleType="centerInside"
+        android:enabled="false"
+        android:alpha="0.5"/>
+    <TextView
+        style="@style/Widget.AppCompat.NotificationActionText"
+        android:id="@+id/action_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center|start"
+        android:textColor="#ccc"
+        android:paddingLeft="4dp"
+        android:paddingStart="4dp"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:clickable="false"
+        android:enabled="false"
+        android:alpha="0.5"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/notification_template_big_media.xml b/v7/appcompat/res/layout/notification_template_big_media.xml
index 2e40b69..b72fd97 100644
--- a/v7/appcompat/res/layout/notification_template_big_media.xml
+++ b/v7/appcompat/res/layout/notification_template_big_media.xml
@@ -20,18 +20,18 @@
     android:layout_width="match_parent"
     android:layout_height="128dp"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="centerCrop"
-        />
+    />
     <include layout="@layout/notification_media_cancel_action"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginLeft="2dp"
         android:layout_marginRight="2dp"
-        android:layout_alignParentRight="true"/>
-    <include layout="@layout/notification_template_lines"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentEnd="true" />
+    <include layout="@layout/notification_template_lines_media"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="fill_vertical"
diff --git a/v7/appcompat/res/layout/notification_template_big_media_custom.xml b/v7/appcompat/res/layout/notification_template_big_media_custom.xml
new file mode 100644
index 0000000..c88d799
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_big_media_custom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="128dp"
+    >
+    <include layout="@layout/notification_template_icon_group"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+    />
+    <include layout="@layout/notification_media_cancel_action"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginLeft="2dp"
+        android:layout_marginRight="2dp"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentEnd="true"/>
+    <LinearLayout
+        android:id="@+id/notification_main_column_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/notification_large_icon_height"
+        android:layout_marginStart="@dimen/notification_large_icon_height"
+        android:minHeight="@dimen/notification_large_icon_height"
+        android:paddingTop="@dimen/notification_main_column_padding_top"
+        android:orientation="horizontal"
+        android:layout_toLeftOf="@id/cancel_action"
+        android:layout_toStartOf="@id/cancel_action">
+        <FrameLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginLeft="@dimen/notification_content_margin_start"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_marginRight="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginBottom="8dp"
+        />
+        <FrameLayout
+            android:id="@+id/right_side"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="8dp"
+            android:layout_marginEnd="8dp"
+            android:paddingTop="@dimen/notification_right_side_padding_top">
+            <DateTimeView android:id="@+id/time"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:layout_gravity="end|top"
+                android:visibility="gone"
+            />
+            <Chronometer android:id="@+id/chronometer"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:layout_gravity="end|top"
+                android:visibility="gone"
+            />
+            <TextView android:id="@+id/info"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:layout_gravity="end|bottom"
+                android:singleLine="true"
+            />
+        </FrameLayout>
+    </LinearLayout>
+    <LinearLayout
+        android:id="@+id/media_actions"
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:layout_alignParentBottom="true"
+        android:layout_marginLeft="12dp"
+        android:layout_marginRight="12dp"
+        android:orientation="horizontal"
+        android:layoutDirection="ltr"
+        >
+        <!-- media buttons will be added here -->
+    </LinearLayout>
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:layout_above="@id/media_actions"
+        android:id="@+id/action_divider"
+        android:background="?android:attr/dividerHorizontal" />
+</RelativeLayout>
diff --git a/v7/appcompat/res/layout/notification_template_big_media_narrow.xml b/v7/appcompat/res/layout/notification_template_big_media_narrow.xml
index cf64061..979c8f4 100644
--- a/v7/appcompat/res/layout/notification_template_big_media_narrow.xml
+++ b/v7/appcompat/res/layout/notification_template_big_media_narrow.xml
@@ -35,7 +35,7 @@
         android:layout_alignParentRight="true"
         android:layout_alignParentEnd="true"/>
 
-    <include layout="@layout/notification_template_lines"
+    <include layout="@layout/notification_template_lines_media"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_marginLeft="128dp"
diff --git a/v7/appcompat/res/layout/notification_template_big_media_narrow_custom.xml b/v7/appcompat/res/layout/notification_template_big_media_narrow_custom.xml
new file mode 100644
index 0000000..b7fbff7
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_big_media_narrow_custom.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- Layout to be used with only max 3 actions. It has a much larger picture at the left side-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="128dp"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="128dp"
+        android:layout_height="128dp"
+        android:scaleType="centerCrop"
+        />
+
+    <include layout="@layout/notification_media_cancel_action"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginLeft="2dp"
+        android:layout_marginRight="2dp"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentEnd="true"/>
+
+    <LinearLayout
+        android:id="@+id/notification_main_column_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="128dp"
+        android:layout_marginStart="128dp"
+        android:minHeight="@dimen/notification_large_icon_height"
+        android:paddingTop="@dimen/notification_main_column_padding_top"
+        android:orientation="horizontal"
+        android:layout_toLeftOf="@id/cancel_action"
+        android:layout_toStartOf="@id/cancel_action">
+        <FrameLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginLeft="@dimen/notification_media_narrow_margin"
+            android:layout_marginStart="@dimen/notification_media_narrow_margin"
+            android:layout_marginRight="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginBottom="8dp"/>
+        <FrameLayout
+            android:id="@+id/right_side"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="8dp"
+            android:layout_marginEnd="8dp"
+            android:paddingTop="@dimen/notification_right_side_padding_top">
+            <DateTimeView android:id="@+id/time"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:layout_gravity="end|top"
+                android:visibility="gone"
+            />
+            <Chronometer android:id="@+id/chronometer"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:layout_gravity="end|top"
+                android:visibility="gone"
+            />
+            <TextView android:id="@+id/info"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:layout_gravity="end|bottom"
+                android:singleLine="true"
+            />
+        </FrameLayout>
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/media_actions"
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:layout_toRightOf="@id/icon"
+        android:layout_toEndOf="@id/icon"
+        android:layout_alignParentBottom="true"
+        android:layout_marginLeft="12dp"
+        android:layout_marginRight="12dp"
+        android:orientation="horizontal"
+        android:layoutDirection="ltr"
+        >
+        <!-- media buttons will be added here -->
+    </LinearLayout>
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:layout_toRightOf="@id/icon"
+        android:layout_toEndOf="@id/icon"
+        android:layout_above="@id/media_actions"
+        android:id="@+id/action_divider"
+        android:background="?android:attr/dividerHorizontal" />
+</RelativeLayout>
diff --git a/v7/appcompat/res/layout/notification_template_custom_big.xml b/v7/appcompat/res/layout/notification_template_custom_big.xml
new file mode 100644
index 0000000..c922629
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_custom_big.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout android:id="@+id/notification_main_column_container"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/notification_large_icon_height"
+    android:orientation="horizontal"
+    android:paddingRight="12dp"
+    android:paddingEnd="12dp">
+    <ImageView android:id="@+id/icon"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+        android:background="@drawable/notification_tile_bg"
+        android:scaleType="center"
+    />
+    <FrameLayout
+        android:id="@+id/notification_main_column"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="12dp"
+        android:paddingStart="12dp"
+        android:paddingTop="@dimen/notification_main_column_padding_top"
+        android:layout_weight="1"/>
+    <FrameLayout
+        android:id="@+id/right_side"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="12dp"
+        android:paddingLeft="12dp">
+        <include
+            layout="@layout/notification_template_part_time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end|top"
+            android:visibility="gone"/>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end|bottom"
+            android:layout_marginTop="18dp"
+            android:orientation="horizontal">
+            <TextView android:id="@+id/info"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:singleLine="true"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info"
+            />
+            <ImageView android:id="@+id/right_icon"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:layout_gravity="center"
+                android:layout_marginLeft="8dp"
+                android:alpha="0.7"
+                android:scaleType="center"
+                android:visibility="gone"
+            />
+        </LinearLayout>
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/notification_template_icon_group.xml b/v7/appcompat/res/layout/notification_template_icon_group.xml
new file mode 100644
index 0000000..dd564f8
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_icon_group.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/icon"
+    android:layout_width="@dimen/notification_large_icon_width"
+    android:layout_height="@dimen/notification_large_icon_height"
+    android:scaleType="centerCrop"
+/>
+
diff --git a/v7/appcompat/res/layout/notification_template_lines.xml b/v7/appcompat/res/layout/notification_template_lines_media.xml
similarity index 70%
rename from v7/appcompat/res/layout/notification_template_lines.xml
rename to v7/appcompat/res/layout/notification_template_lines_media.xml
index 42ba776..9a7b788 100644
--- a/v7/appcompat/res/layout/notification_template_lines.xml
+++ b/v7/appcompat/res/layout/notification_template_lines_media.xml
@@ -29,12 +29,12 @@
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:paddingTop="6dp"
-        android:layout_marginLeft="8dp"
-        android:layout_marginStart="8dp"
+        android:layout_marginLeft="@dimen/notification_content_margin_start"
+        android:layout_marginStart="@dimen/notification_content_margin_start"
         android:orientation="horizontal"
         >
         <TextView android:id="@+id/title"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+            android:textAppearance="@style/TextAppearance.AppCompat.Notification.Title.Media"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:singleLine="true"
@@ -42,33 +42,37 @@
             android:fadingEdge="horizontal"
             android:layout_weight="1"
             />
-        <include
-            layout="@layout/notification_template_part_time"
-            android:id="@+id/time"
+        <DateTimeView android:id="@+id/time"
+            android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:singleLine="true"
             android:layout_gravity="center"
             android:layout_weight="0"
             android:visibility="gone"
-            />
-        <include
-            layout="@layout/notification_template_part_chronometer"
-            android:id="@+id/chronometer"
+            android:paddingLeft="8dp"
+            android:paddingStart="8dp"
+        />
+        <Chronometer android:id="@+id/chronometer"
+            android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:singleLine="true"
             android:layout_gravity="center"
             android:layout_weight="0"
             android:visibility="gone"
-            />
+            android:paddingLeft="8dp"
+            android:paddingStart="8dp"
+        />
     </LinearLayout>
     <TextView android:id="@+id/text2"
-        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
+        android:textAppearance="@style/TextAppearance.AppCompat.Notification.Line2.Media"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="-2dp"
         android:layout_marginBottom="-2dp"
-        android:layout_marginLeft="8dp"
-        android:layout_marginStart="8dp"
+        android:layout_marginLeft="@dimen/notification_content_margin_start"
+        android:layout_marginStart="@dimen/notification_content_margin_start"
         android:singleLine="true"
         android:fadingEdge="horizontal"
         android:ellipsize="marquee"
@@ -80,11 +84,11 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         android:gravity="center_vertical"
-        android:layout_marginLeft="8dp"
-        android:layout_marginStart="8dp"
+        android:layout_marginLeft="@dimen/notification_content_margin_start"
+        android:layout_marginStart="@dimen/notification_content_margin_start"
         >
         <TextView android:id="@+id/text"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+            android:textAppearance="@style/TextAppearance.AppCompat.Notification.Media"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
@@ -94,7 +98,7 @@
             android:fadingEdge="horizontal"
             />
         <TextView android:id="@+id/info"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+            android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
diff --git a/v7/appcompat/res/layout/notification_template_media.xml b/v7/appcompat/res/layout/notification_template_media.xml
index 90daa88..6eac23b7 100644
--- a/v7/appcompat/res/layout/notification_template_media.xml
+++ b/v7/appcompat/res/layout/notification_template_media.xml
@@ -21,12 +21,11 @@
     android:layout_height="64dp"
     android:orientation="horizontal"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_width"
-        android:scaleType="centerCrop"
-        />
-    <include layout="@layout/notification_template_lines"
+        android:layout_height="@dimen/notification_large_icon_height"
+    />
+    <include layout="@layout/notification_template_lines_media"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"/>
diff --git a/v7/appcompat/res/layout/notification_template_media_custom.xml b/v7/appcompat/res/layout/notification_template_media_custom.xml
new file mode 100644
index 0000000..62e07d4
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_media_custom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="64dp"
+    android:orientation="horizontal"
+    >
+    <include layout="@layout/notification_template_icon_group"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+    />
+    <LinearLayout
+        android:id="@+id/notification_main_column_container"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/notification_main_column_padding_top"
+        android:minHeight="@dimen/notification_large_icon_height"
+        android:orientation="horizontal"
+        android:layout_toLeftOf="@id/cancel_action"
+        android:layout_toStartOf="@id/cancel_action">
+        <FrameLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginLeft="@dimen/notification_content_margin_start"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_marginRight="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginBottom="8dp"/>
+        <FrameLayout
+            android:id="@+id/right_side"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="8dp"
+            android:layout_marginEnd="8dp"
+            android:paddingTop="@dimen/notification_right_side_padding_top">
+            <DateTimeView android:id="@+id/time"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:layout_gravity="end|top"
+                android:visibility="gone"
+            />
+            <Chronometer android:id="@+id/chronometer"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:layout_gravity="end|top"
+                android:visibility="gone"
+            />
+            <TextView android:id="@+id/info"
+                android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:layout_gravity="end|bottom"
+                android:singleLine="true"
+            />
+        </FrameLayout>
+    </LinearLayout>
+    <LinearLayout
+        android:id="@+id/media_actions"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="center_vertical|end"
+        android:orientation="horizontal"
+        android:layoutDirection="ltr"
+        >
+        <!-- media buttons will be added here -->
+    </LinearLayout>
+    <include layout="@layout/notification_media_cancel_action"
+        android:layout_width="48dp"
+        android:layout_height="match_parent"
+        android:layout_marginRight="6dp"
+        android:layout_marginEnd="6dp"/>
+    <ImageView android:id="@+id/end_padder"
+        android:layout_width="6dp"
+        android:layout_height="match_parent"
+        />
+</LinearLayout>
diff --git a/v7/appcompat/res/layout/notification_template_part_chronometer.xml b/v7/appcompat/res/layout/notification_template_part_chronometer.xml
index 6f5f3ac..9e58a38 100644
--- a/v7/appcompat/res/layout/notification_template_part_chronometer.xml
+++ b/v7/appcompat/res/layout/notification_template_part_chronometer.xml
@@ -16,13 +16,8 @@
   -->
 
 <Chronometer android:id="@+id/chronometer" xmlns:android="http://schemas.android.com/apk/res/android"
-    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Time"
+    android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:layout_weight="0"
     android:singleLine="true"
-    android:gravity="center"
-    android:paddingLeft="8dp"
-    android:paddingStart="8dp"
     />
diff --git a/v7/appcompat/res/layout/notification_template_part_time.xml b/v7/appcompat/res/layout/notification_template_part_time.xml
index 72d216e..810d1e3 100644
--- a/v7/appcompat/res/layout/notification_template_part_time.xml
+++ b/v7/appcompat/res/layout/notification_template_part_time.xml
@@ -16,13 +16,8 @@
   -->
 
 <DateTimeView android:id="@+id/time" xmlns:android="http://schemas.android.com/apk/res/android"
-    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Time"
+    android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:layout_weight="0"
     android:singleLine="true"
-    android:gravity="center"
-    android:paddingLeft="8dp"
-    android:paddingStart="8dp"
     />
diff --git a/v7/appcompat/res/values-my-rMM/strings.xml b/v7/appcompat/res/values-my-rMM/strings.xml
index 93f779d..0248c15 100644
--- a/v7/appcompat/res/values-my-rMM/strings.xml
+++ b/v7/appcompat/res/values-my-rMM/strings.xml
@@ -27,7 +27,7 @@
     <string name="abc_search_hint" msgid="7723749260725869598">"ရှာဖွေပါ..."</string>
     <string name="abc_searchview_description_query" msgid="2550479030709304392">"ရှာစရာ အချက်အလက်နေရာ"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ရှာစရာ အချက်အလက်များ ဖယ်ရှားရန်"</string>
-    <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ရှာဖွေစရာ အချက်အလက်ကို အတည်ပြုရန်"</string>
+    <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ရှာဖွေစရာ အချက်အလက်ကို ပေးပို့ရန်"</string>
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"အသံဖြင့် ရှာဖွေခြင်း"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"အက်ပ်တစ်ခုခုကို ရွေးချယ်ပါ"</string>
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"အားလုံးကို ကြည့်ရန်"</string>
diff --git a/v7/appcompat/res/values-v14/styles.xml b/v7/appcompat/res/values-v14/styles.xml
index f54796d..39419d2 100644
--- a/v7/appcompat/res/values-v14/styles.xml
+++ b/v7/appcompat/res/values-v14/styles.xml
@@ -30,4 +30,9 @@
     <style name="TextAppearance.StatusBar.EventContent.Info"/>
     <style name="TextAppearance.StatusBar.EventContent.Time"/>
 
+    <style name="TextAppearance.AppCompat.Notification.Title"
+        parent="@android:style/TextAppearance.StatusBar.EventContent.Title"/>
+
+    <style name="TextAppearance.AppCompat.Notification"
+        parent="@android:style/TextAppearance.StatusBar.EventContent"/>
 </resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v16/dimens.xml b/v7/appcompat/res/values-v16/dimens.xml
new file mode 100644
index 0000000..3280f7b
--- /dev/null
+++ b/v7/appcompat/res/values-v16/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <!-- the paddingtop on the right side of the notification (for time etc.) -->
+    <dimen name="notification_right_side_padding_top">4dp</dimen>
+</resources>
diff --git a/v7/appcompat/res/values-v21/colors.xml b/v7/appcompat/res/values-v21/colors.xml
new file mode 100644
index 0000000..4a1b209
--- /dev/null
+++ b/v7/appcompat/res/values-v21/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <color name="notification_action_color_filter">@color/secondary_text_default_material_light</color>
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v21/dimens.xml b/v7/appcompat/res/values-v21/dimens.xml
new file mode 100644
index 0000000..de665a6
--- /dev/null
+++ b/v7/appcompat/res/values-v21/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- the margin at the beginning of the notification content -->
+    <dimen name="notification_content_margin_start">0dp</dimen>
+    <!-- image margin on the large icon in the narrow media template -->
+    <dimen name="notification_media_narrow_margin">12dp</dimen>
+    <!-- the top padding of the notification content -->
+    <dimen name="notification_main_column_padding_top">0dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v21/styles.xml b/v7/appcompat/res/values-v21/styles.xml
new file mode 100644
index 0000000..1c435ae
--- /dev/null
+++ b/v7/appcompat/res/values-v21/styles.xml
@@ -0,0 +1,58 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+
+    <!-- Use platform styles -->
+    <style name="TextAppearance.AppCompat.Notification.Info"
+        parent="@android:style/TextAppearance.Material.Notification.Info"/>
+
+    <style name="TextAppearance.AppCompat.Notification.Time"
+        parent="@android:style/TextAppearance.Material.Notification.Time"/>
+
+    <style name="TextAppearance.AppCompat.Notification.Title"
+        parent="@android:style/TextAppearance.Material.Notification.Title"/>
+
+    <style name="TextAppearance.AppCompat.Notification"
+        parent="@android:style/TextAppearance.Material.Notification"/>
+
+    <style name="TextAppearance.AppCompat.Notification.Media" >
+        <item name="android:textColor">@color/secondary_text_default_material_dark</item>
+    </style>
+
+    <style name="TextAppearance.AppCompat.Notification.Title.Media" >
+        <item name="android:textColor">@color/primary_text_default_material_dark</item>
+    </style>
+
+    <style name="TextAppearance.AppCompat.Notification.Info.Media">
+        <item name="android:textColor">@color/secondary_text_default_material_dark</item>
+    </style>
+
+    <style name="TextAppearance.AppCompat.Notification.Time.Media">
+        <item name="android:textColor">@color/secondary_text_default_material_dark</item>
+    </style>
+
+    <style name="Widget.AppCompat.NotificationActionText" parent="">
+        <item name="android:textAppearance">?android:attr/textAppearanceButton</item>
+        <item name="android:textColor">@color/secondary_text_default_material_light</item>
+        <item name="android:textSize">@dimen/notification_action_text_size</item>
+    </style>
+
+    <style name="Widget.AppCompat.NotificationActionContainer" parent="">
+        <item name="android:background">@drawable/notification_action_background</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v24/styles.xml b/v7/appcompat/res/values-v24/styles.xml
new file mode 100644
index 0000000..52bb3d4
--- /dev/null
+++ b/v7/appcompat/res/values-v24/styles.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+
+    <!-- Use platform styles, Media is dark again -->
+    <style name="TextAppearance.AppCompat.Notification.Media" />
+
+    <style name="TextAppearance.AppCompat.Notification.Info.Media" />
+
+    <style name="TextAppearance.AppCompat.Notification.Time.Media" />
+
+    <style name="TextAppearance.AppCompat.Notification.Title.Media" />
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/colors.xml b/v7/appcompat/res/values/colors.xml
index 0ce01d2..92c91fd 100644
--- a/v7/appcompat/res/values/colors.xml
+++ b/v7/appcompat/res/values/colors.xml
@@ -21,4 +21,11 @@
     <color name="abc_input_method_navigation_guard">@android:color/black</color>
 
     <drawable name="notification_template_icon_bg">#3333B5E5</drawable>
+    <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
+    <color name="notification_action_color_filter">#ffffffff</color>
+    <color name="notification_icon_bg_color">#ff9e9e9e</color>
+
+    <!-- The color of the material notification background for media notifications when no custom
+     color is specified -->
+    <color name="notification_material_background_media_default_color">#ff424242</color>
 </resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/dimens.xml b/v7/appcompat/res/values/dimens.xml
index 69928ae..7467beb 100644
--- a/v7/appcompat/res/values/dimens.xml
+++ b/v7/appcompat/res/values/dimens.xml
@@ -103,5 +103,41 @@
 
     <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info,
          Time) -->
-    <dimen name="notification_subtext_size">12dp</dimen>
+    <dimen name="notification_subtext_size">13sp</dimen>
+
+    <!-- Size of notification action text -->
+    <dimen name="notification_action_text_size">13sp</dimen>
+
+    <!-- Top padding for notifications in the standard layout. -->
+    <dimen name="notification_top_pad">10dp</dimen>
+
+    <!-- Top padding for notification when text is large -->
+    <dimen name="notification_top_pad_large_text">5dp</dimen>
+
+    <!-- The size of the action icons -->
+    <dimen name="notification_action_icon_size">32dp</dimen>
+
+    <!-- the size of the small icon on the right of the largeIcon -->
+    <dimen name="notification_right_icon_size">16dp</dimen>
+
+    <!-- the padding of the small icon to the circle -->
+    <dimen name="notification_small_icon_background_padding">3dp</dimen>
+
+    <!-- the side margin of the big notification circle -->
+    <dimen name="notification_big_circle_margin">12dp</dimen>
+
+    <!-- small icon size when placed as large icon -->
+    <dimen name="notification_small_icon_size_as_large">24dp</dimen>
+
+    <!-- the margin at the beginning of the notification content -->
+    <dimen name="notification_content_margin_start">8dp</dimen>
+
+    <!-- image margin on the large icon in the narrow media template -->
+    <dimen name="notification_media_narrow_margin">@dimen/notification_content_margin_start</dimen>
+
+    <!-- the top padding of the notification content -->
+    <dimen name="notification_main_column_padding_top">10dp</dimen>
+
+    <!-- the paddingtop on the right side of the notification (for time etc.) -->
+    <dimen name="notification_right_side_padding_top">2dp</dimen>
 </resources>
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index ad86cbd..ec8bbe1 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -329,4 +329,35 @@
     <style name="TextAppearance.StatusBar.EventContent.Line2" parent=""/>
     <style name="TextAppearance.StatusBar.EventContent.Info" parent=""/>
     <style name="TextAppearance.StatusBar.EventContent.Time" parent=""/>
+
+    <style name="TextAppearance.AppCompat.Notification">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+    <style name="TextAppearance.AppCompat.Notification.Title">
+        <item name="android:textSize">16sp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+    <style name="TextAppearance.AppCompat.Notification.Info">
+        <item name="android:textSize">12sp</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+    <style name="TextAppearance.AppCompat.Notification.Time">
+        <item name="android:textSize">12sp</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+    <style name="TextAppearance.AppCompat.Notification.Line2" parent="TextAppearance.AppCompat.Notification.Info" />
+
+    <style name="TextAppearance.AppCompat.Notification.Title.Media" />
+
+    <style name="TextAppearance.AppCompat.Notification.Media" />
+
+    <style name="TextAppearance.AppCompat.Notification.Info.Media"/>
+
+    <style name="TextAppearance.AppCompat.Notification.Time.Media"/>
+
+    <style name="TextAppearance.AppCompat.Notification.Line2.Media" parent="TextAppearance.AppCompat.Notification.Info.Media"/>
+
+    <style name="Widget.AppCompat.NotificationActionText" parent=""/>
+    <style name="Widget.AppCompat.NotificationActionContainer" parent=""/>
 </resources>
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index 581385d..a421ae4 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -584,6 +584,7 @@
         <item name="android:colorForegroundInverse">@color/foreground_material_dark</item>
         <item name="android:colorBackground">@color/background_material_light</item>
         <item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_light</item>
+        <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
 
         <item name="android:textColorPrimary">@color/abc_primary_text_material_light</item>
         <item name="android:textColorPrimaryInverse">@color/abc_primary_text_material_dark</item>
@@ -612,6 +613,7 @@
         <item name="android:colorForegroundInverse">@color/foreground_material_light</item>
         <item name="android:colorBackground">@color/background_material_dark</item>
         <item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
 
         <item name="android:textColorPrimary">@color/abc_primary_text_material_dark</item>
         <item name="android:textColorPrimaryInverse">@color/abc_primary_text_material_light</item>
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
index d1c938f..6a3c91f 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
@@ -19,6 +19,8 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -26,11 +28,22 @@
 import android.support.v4.app.BundleCompat;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
 import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.text.BidiFormatter;
+import android.support.v7.appcompat.R;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
+import android.widget.RemoteViews;
+
+import java.util.List;
 
 /**
  * An extension of {@link android.support.v4.app.NotificationCompat} which supports
- * {@link android.support.v7.app.NotificationCompat.MediaStyle}. You should start using this variant
- * if you need support for media styled notifications.
+ * {@link android.support.v7.app.NotificationCompat.MediaStyle},
+ * {@link android.support.v7.app.NotificationCompat.DecoratedCustomViewStyle},
+ * and {@link android.support.v7.app.NotificationCompat.DecoratedMediaCustomViewStyle}.
+ * You should start using this variant if you need support any of these styles.
  */
 public class NotificationCompat extends android.support.v4.app.NotificationCompat {
 
@@ -66,46 +79,288 @@
         return null;
     }
 
-    private static void addMediaStyleToBuilderLollipop(
-            NotificationBuilderWithBuilderAccessor builder, android.support.v4.app.NotificationCompat.Style style) {
-        if (style instanceof MediaStyle) {
-            MediaStyle mediaStyle = (MediaStyle) style;
+    private static void addStyleToBuilderApi24(NotificationBuilderWithBuilderAccessor builder,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        if (b.mStyle instanceof DecoratedCustomViewStyle) {
+            NotificationCompatImpl24.addDecoratedCustomViewStyle(builder);
+        } else if (b.mStyle instanceof DecoratedMediaCustomViewStyle) {
+            NotificationCompatImpl24.addDecoratedMediaCustomViewStyle(builder);
+        } else if (!(b.mStyle instanceof MessagingStyle)) {
+            addStyleGetContentViewLollipop(builder, b);
+        }
+    }
+
+    private static RemoteViews addStyleGetContentViewLollipop(
+            NotificationBuilderWithBuilderAccessor builder,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        if (b.mStyle instanceof MediaStyle) {
+            MediaStyle mediaStyle = (MediaStyle) b.mStyle;
             NotificationCompatImpl21.addMediaStyle(builder,
                     mediaStyle.mActionsToShowInCompact,
                     mediaStyle.mToken != null ? mediaStyle.mToken.getToken() : null);
+
+            boolean hasContentView = b.getContentView() != null;
+            // If we are on L/M the media notification will only be colored if the expanded version
+            // is of media style, so we have to create a custom view for the collapsed version as
+            // well in that case.
+            boolean isMorL = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+                    && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M;
+            boolean createCustomContent = hasContentView
+                    || (isMorL && b.getBigContentView() != null);
+            if (b.mStyle instanceof DecoratedMediaCustomViewStyle && createCustomContent) {
+                RemoteViews contentViewMedia = NotificationCompatImplBase.overrideContentViewMedia(
+                        builder, b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo,
+                        b.mNumber, b.mLargeIcon, b.mSubText, b.mUseChronometer,
+                        b.getWhenIfShowing(), b.getPriority(), b.mActions,
+                        mediaStyle.mActionsToShowInCompact, false /* no cancel button on L */,
+                        null /* cancelButtonIntent */, hasContentView /* isDecoratedCustomView */);
+                if (hasContentView) {
+                    NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, contentViewMedia,
+                            b.getContentView());
+                }
+                setBackgroundColor(b.mContext, contentViewMedia, b.getColor());
+                return contentViewMedia;
+            }
+            return null;
+        } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+            return getDecoratedContentView(b);
         }
+        return addStyleGetContentViewJellybean(builder, b);
     }
 
-    private static void addMediaStyleToBuilderIcs(NotificationBuilderWithBuilderAccessor builder,
+    private static RemoteViews addStyleGetContentViewJellybean(
+            NotificationBuilderWithBuilderAccessor builder,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        if (b.mStyle instanceof MessagingStyle) {
+            addMessagingFallBackStyle((MessagingStyle) b.mStyle, builder, b);
+        }
+        return addStyleGetContentViewIcs(builder, b);
+    }
+
+    private static MessagingStyle.Message findLatestIncomingMessage(MessagingStyle style) {
+        List<MessagingStyle.Message> messages = style.getMessages();
+        for (int i = messages.size() - 1; i >= 0; i--) {
+            MessagingStyle.Message m = messages.get(i);
+            // Incoming messages have a non-empty sender.
+            if (!TextUtils.isEmpty(m.getSender())) {
+                return m;
+            }
+        }
+        if (!messages.isEmpty()) {
+            // No incoming messages, fall back to outgoing message
+            return messages.get(messages.size() - 1);
+        }
+        return null;
+    }
+
+    private static CharSequence makeMessageLine(android.support.v4.app.NotificationCompat.Builder b,
+            MessagingStyle style,
+            MessagingStyle.Message m) {
+        BidiFormatter bidi = BidiFormatter.getInstance();
+        SpannableStringBuilder sb = new SpannableStringBuilder();
+        boolean afterLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+        int color = afterLollipop || Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1
+                ? Color.BLACK : Color.WHITE;
+        CharSequence replyName = m.getSender();
+        if (TextUtils.isEmpty(m.getSender())) {
+            replyName = style.getUserDisplayName() == null
+                    ? "" : style.getUserDisplayName();
+            color = afterLollipop && b.getColor() != NotificationCompat.COLOR_DEFAULT
+                    ? b.getColor()
+                    : color;
+        }
+        CharSequence senderText = bidiWrapIfNotSpanned(bidi, replyName);
+        sb.append(senderText);
+        sb.setSpan(makeFontColorSpan(color),
+                sb.length() - senderText.length(),
+                sb.length(),
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE /* flags */);
+        CharSequence text = m.getText() == null ? "" : m.getText();
+        sb.append("  ").append(bidiWrapIfNotSpanned(bidi, text));
+        return sb;
+    }
+
+    private static CharSequence bidiWrapIfNotSpanned(BidiFormatter bidi, CharSequence replyName) {
+        // Unfortunately bidiFormatter doesn't support CharSequences in support
+        if (replyName instanceof Spanned) {
+            return replyName;
+        }
+        return bidi.unicodeWrap(replyName.toString());
+    }
+
+    private static TextAppearanceSpan makeFontColorSpan(int color) {
+        return new TextAppearanceSpan(null, 0, 0, ColorStateList.valueOf(color), null);
+    }
+
+    private static void addMessagingFallBackStyle(MessagingStyle style,
+            NotificationBuilderWithBuilderAccessor builder,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        SpannableStringBuilder completeMessage = new SpannableStringBuilder();
+        List<MessagingStyle.Message> messages = style.getMessages();
+        boolean showNames = style.getConversationTitle() != null
+                || hasMessagesWithoutSender(style.getMessages());
+        for (int i = messages.size() - 1; i >= 0; i--) {
+            MessagingStyle.Message m = messages.get(i);
+            CharSequence line;
+            line = showNames ? makeMessageLine(b, style, m) : m.getText();
+            if (i != messages.size() - 1) {
+                completeMessage.insert(0, "\n");
+            }
+            completeMessage.insert(0, line);
+        }
+        NotificationCompatImplJellybean.addBigTextStyle(builder, completeMessage);
+    }
+
+    private static boolean hasMessagesWithoutSender(
+            List<MessagingStyle.Message> messages) {
+        for (int i = messages.size() - 1; i >= 0; i--) {
+            MessagingStyle.Message m = messages.get(i);
+            if (m.getSender() == null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static RemoteViews addStyleGetContentViewIcs(
+            NotificationBuilderWithBuilderAccessor builder,
             android.support.v4.app.NotificationCompat.Builder b) {
         if (b.mStyle instanceof MediaStyle) {
             MediaStyle mediaStyle = (MediaStyle) b.mStyle;
-            NotificationCompatImplBase.overrideContentView(builder, b.mContext,
-                    b.mContentTitle,
-                    b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText,
-                    b.mUseChronometer, b.mNotification.when, b.mActions,
-                    mediaStyle.mActionsToShowInCompact, mediaStyle.mShowCancelButton,
-                    mediaStyle.mCancelButtonIntent);
+            boolean isDecorated = b.mStyle instanceof DecoratedMediaCustomViewStyle
+                    && b.getContentView() != null;
+            RemoteViews contentViewMedia = NotificationCompatImplBase.overrideContentViewMedia(
+                    builder, b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+                    b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(),
+                    b.getPriority(), b.mActions, mediaStyle.mActionsToShowInCompact,
+                    mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent, isDecorated);
+            if (isDecorated) {
+                NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, contentViewMedia,
+                        b.getContentView());
+                return contentViewMedia;
+            }
+        } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+            return getDecoratedContentView(b);
         }
+        return null;
     }
 
-    private static void addBigMediaStyleToBuilderJellybean(Notification n,
+    private static void addBigStyleToBuilderJellybean(Notification n,
             android.support.v4.app.NotificationCompat.Builder b) {
         if (b.mStyle instanceof MediaStyle) {
             MediaStyle mediaStyle = (MediaStyle) b.mStyle;
-            NotificationCompatImplBase.overrideBigContentView(n, b.mContext,
-                    b.mContentTitle,
-                    b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText,
-                    b.mUseChronometer, b.mNotification.when, b.mActions,
-                    mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent);
-            Bundle extras = getExtras(n);
-            if (mediaStyle.mToken != null) {
-                BundleCompat.putBinder(extras, EXTRA_MEDIA_SESSION,
-                        (IBinder) mediaStyle.mToken.getToken());
+            RemoteViews innerView = b.getBigContentView() != null
+                    ? b.getBigContentView()
+                    : b.getContentView();
+            boolean isDecorated = b.mStyle instanceof DecoratedMediaCustomViewStyle
+                    && innerView != null;
+            NotificationCompatImplBase.overrideMediaBigContentView(n, b.mContext,
+                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon,
+                    b.mSubText, b.mUseChronometer, b.getWhenIfShowing(), b.getPriority(), 0,
+                    b.mActions, mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent,
+                    isDecorated);
+            if (isDecorated) {
+                NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, n.bigContentView,
+                        innerView);
             }
-            if (mediaStyle.mActionsToShowInCompact != null) {
-                extras.putIntArray(EXTRA_COMPACT_ACTIONS, mediaStyle.mActionsToShowInCompact);
-            }
+        } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+            addDecoratedBigStyleToBuilder(n, b);
+        }
+    }
+
+    private static RemoteViews getDecoratedContentView(
+            android.support.v4.app.NotificationCompat.Builder b) {
+        if (b.getContentView() == null) {
+            // No special content view
+            return null;
+        }
+        RemoteViews remoteViews = NotificationCompatImplBase.applyStandardTemplateWithActions(
+                b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+                b.mNotification.icon, b.mLargeIcon, b.mSubText, b.mUseChronometer,
+                b.getWhenIfShowing(), b.getPriority(), b.getColor(),
+                R.layout.notification_template_custom_big, false /* fitIn1U */, null /* actions */);
+        NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, remoteViews,
+                b.getContentView());
+        return remoteViews;
+    }
+
+    private static void addDecoratedBigStyleToBuilder(Notification n,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        RemoteViews bigContentView = b.getBigContentView();
+        RemoteViews innerView = bigContentView != null ? bigContentView : b.getContentView();
+        if (innerView == null) {
+            // No expandable notification
+            return;
+        }
+        RemoteViews remoteViews = NotificationCompatImplBase.applyStandardTemplateWithActions(
+                b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+                n.icon ,b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(),
+                b.getPriority(), b.getColor(), R.layout.notification_template_custom_big,
+                false /* fitIn1U */, b.mActions);
+        NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, remoteViews, innerView);
+        n.bigContentView = remoteViews;
+    }
+
+    private static void addDecoratedHeadsUpToBuilder(Notification n,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        RemoteViews headsUp = b.getHeadsUpContentView();
+        RemoteViews innerView = headsUp != null ? headsUp : b.getContentView();
+        if (headsUp == null) {
+            // No expandable notification
+            return;
+        }
+        RemoteViews remoteViews = NotificationCompatImplBase.applyStandardTemplateWithActions(
+                b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber, n.icon,
+                b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(), b.getPriority(),
+                b.getColor(), R.layout.notification_template_custom_big, false /* fitIn1U */,
+                b.mActions);
+        NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, remoteViews, innerView);
+        n.headsUpContentView = remoteViews;
+    }
+
+    private static void addBigStyleToBuilderLollipop(Notification n,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        RemoteViews innerView = b.getBigContentView() != null
+                ? b.getBigContentView()
+                : b.getContentView();
+        if (b.mStyle instanceof DecoratedMediaCustomViewStyle && innerView != null) {
+            NotificationCompatImplBase.overrideMediaBigContentView(n, b.mContext,
+                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon,
+                    b.mSubText, b.mUseChronometer, b.getWhenIfShowing(), b.getPriority(), 0,
+                    b.mActions, false /* showCancelButton */, null /* cancelButtonIntent */,
+                    true /* decoratedCustomView */);
+                    NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, n.bigContentView,
+                            innerView);
+            setBackgroundColor(b.mContext, n.bigContentView, b.getColor());
+        } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+            addDecoratedBigStyleToBuilder(n, b);
+        }
+    }
+
+    private static void setBackgroundColor(Context context, RemoteViews views, int color) {
+        if (color == COLOR_DEFAULT) {
+            color = context.getResources().getColor(
+                    R.color.notification_material_background_media_default_color);
+        }
+        views.setInt(R.id.status_bar_latest_event_content, "setBackgroundColor", color);
+    }
+
+    private static void addHeadsUpToBuilderLollipop(Notification n,
+            android.support.v4.app.NotificationCompat.Builder b) {
+        RemoteViews innerView = b.getHeadsUpContentView() != null
+                ? b.getHeadsUpContentView()
+                : b.getContentView();
+        if (b.mStyle instanceof DecoratedMediaCustomViewStyle && innerView != null) {
+            n.headsUpContentView = NotificationCompatImplBase.generateMediaBigView(b.mContext,
+                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+                    b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(),
+                    b.getPriority(), 0, b.mActions, false /* showCancelButton */,
+                    null /* cancelButtonIntent */, true /* decoratedCustomView */);
+            NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, n.headsUpContentView,
+                    innerView);
+            setBackgroundColor(b.mContext, n.headsUpContentView, b.getColor());
+        } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+            addDecoratedHeadsUpToBuilder(n, b);
         }
     }
 
@@ -123,11 +378,50 @@
         }
 
         /**
+         * @return the text of the notification
+         *
+         * @hide
+         */
+        @Override
+        protected CharSequence resolveText() {
+            if (mStyle instanceof MessagingStyle) {
+                MessagingStyle style = (MessagingStyle) mStyle;
+                MessagingStyle.Message m = findLatestIncomingMessage(style);
+                CharSequence conversationTitle = style.getConversationTitle();
+                if (m != null) {
+                    return conversationTitle != null ? makeMessageLine(this, style, m)
+                            : m.getText();
+                }
+            }
+            return super.resolveText();
+        }
+
+        /**
+         * @return the title of the notification
+         *
+         * @hide
+         */
+        @Override
+        protected CharSequence resolveTitle() {
+            if (mStyle instanceof MessagingStyle) {
+                MessagingStyle style = (MessagingStyle) mStyle;
+                MessagingStyle.Message m = findLatestIncomingMessage(style);
+                CharSequence conversationTitle = style.getConversationTitle();
+                if (conversationTitle != null || m != null) {
+                    return conversationTitle != null ? conversationTitle : m.getSender();
+                }
+            }
+            return super.resolveTitle();
+        }
+
+        /**
          * @hide
          */
         @Override
         protected BuilderExtender getExtender() {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                return new Api24Extender();
+            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                 return new LollipopExtender();
             } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                 return new JellybeanExtender();
@@ -144,8 +438,16 @@
         @Override
         public Notification build(android.support.v4.app.NotificationCompat.Builder b,
                 NotificationBuilderWithBuilderAccessor builder) {
-            addMediaStyleToBuilderIcs(builder, b);
-            return builder.build();
+            RemoteViews contentView = addStyleGetContentViewIcs(builder, b);
+            Notification n = builder.build();
+            // The above call might override decorated content views again, let's make sure it
+            // sticks.
+            if (contentView != null) {
+                n.contentView = contentView;
+            } else if (b.getContentView() != null) {
+                n.contentView = b.getContentView();
+            }
+            return n;
         }
     }
 
@@ -154,9 +456,14 @@
         @Override
         public Notification build(android.support.v4.app.NotificationCompat.Builder b,
                 NotificationBuilderWithBuilderAccessor builder) {
-            addMediaStyleToBuilderIcs(builder, b);
+            RemoteViews contentView = addStyleGetContentViewJellybean(builder, b);
             Notification n = builder.build();
-            addBigMediaStyleToBuilderJellybean(n, b);
+            // The above call might override decorated content views again, let's make sure it
+            // sticks.
+            if (contentView != null) {
+                n.contentView = contentView;
+            }
+            addBigStyleToBuilderJellybean(n, b);
             return n;
         }
     }
@@ -166,7 +473,25 @@
         @Override
         public Notification build(android.support.v4.app.NotificationCompat.Builder b,
                 NotificationBuilderWithBuilderAccessor builder) {
-            addMediaStyleToBuilderLollipop(builder, b.mStyle);
+            RemoteViews contentView = addStyleGetContentViewLollipop(builder, b);
+            Notification n = builder.build();
+            // The above call might override decorated content views again, let's make sure it
+            // sticks.
+            if (contentView != null) {
+                n.contentView = contentView;
+            }
+            addBigStyleToBuilderLollipop(n, b);
+            addHeadsUpToBuilderLollipop(n, b);
+            return n;
+        }
+    }
+
+    private static class Api24Extender extends BuilderExtender {
+
+        @Override
+        public Notification build(android.support.v4.app.NotificationCompat.Builder b,
+                NotificationBuilderWithBuilderAccessor builder) {
+            addStyleToBuilderApi24(builder, b);
             return builder.build();
         }
     }
@@ -284,4 +609,78 @@
             return this;
         }
     }
+
+
+    /**
+     * Notification style for custom views that are decorated by the system.
+     *
+     * <p>Instead of providing a notification that is completely custom, a developer can set this
+     * style and still obtain system decorations like the notification header with the expand
+     * affordance and actions.
+     *
+     * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+     * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+     * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+     * corresponding custom views to display.
+     *
+     * <p>To use this style with your Notification, feed it to
+     * {@link NotificationCompat.Builder#setStyle(Style)} like so:
+     * <pre class="prettyprint">
+     * Notification noti = new NotificationCompat.Builder()
+     *     .setSmallIcon(R.drawable.ic_stat_player)
+     *     .setLargeIcon(albumArtBitmap))
+     *     .setCustomContentView(contentView);
+     *     .setStyle(<b>new NotificationCompat.DecoratedCustomViewStyle()</b>)
+     *     .build();
+     * </pre>
+     *
+     * <p>If you are using this style, consider using the corresponding styles like
+     * {@link android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification} or
+     * {@link android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification_Title} in
+     * your custom views in order to get the correct styling on each platform version.
+     */
+    public static class DecoratedCustomViewStyle extends Style {
+
+        public DecoratedCustomViewStyle() {
+        }
+    }
+
+    /**
+     * Notification style for media custom views that are decorated by the system.
+     *
+     * <p>Instead of providing a media notification that is completely custom, a developer can set
+     * this style and still obtain system decorations like the notification header with the expand
+     * affordance and actions.
+     *
+     * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+     * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+     * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+     * corresponding custom views to display.
+     *
+     * <p>To use this style with your Notification, feed it to
+     * {@link NotificationCompat.Builder#setStyle(Style)} like so:
+     * <pre class="prettyprint">
+     * Notification noti = new Notification.Builder()
+     *     .setSmallIcon(R.drawable.ic_stat_player)
+     *     .setLargeIcon(albumArtBitmap))
+     *     .setCustomContentView(contentView);
+     *     .setStyle(<b>new NotificationCompat.DecoratedMediaCustomViewStyle()</b>
+     *          .setMediaSession(mySession))
+     *     .build();
+     * </pre>
+     *
+     * <p>If you are using this style, consider using the corresponding styles like
+     * {@link android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification_Media} or
+     * {@link
+     * android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification_Title_Media} in
+     * your custom views in order to get the correct styling on each platform version.
+     *
+     * @see DecoratedCustomViewStyle
+     * @see MediaStyle
+     */
+    public static class DecoratedMediaCustomViewStyle extends MediaStyle {
+
+        public DecoratedMediaCustomViewStyle() {
+        }
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java
new file mode 100644
index 0000000..0547ad4
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.app;
+
+import android.app.Notification;
+import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
+
+class NotificationCompatImpl24 {
+
+    public static void addDecoratedCustomViewStyle(NotificationBuilderWithBuilderAccessor b) {
+        Notification.Builder builder = b.getBuilder();
+        builder.setStyle(new Notification.DecoratedCustomViewStyle());
+    }
+
+    public static void addDecoratedMediaCustomViewStyle(NotificationBuilderWithBuilderAccessor b) {
+        Notification.Builder builder = b.getBuilder();
+        builder.setStyle(new Notification.DecoratedMediaCustomViewStyle());
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
index 2bd772c..a37c921 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
@@ -21,9 +21,15 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.SystemClock;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
+import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationCompatBase;
 import android.support.v7.appcompat.R;
 import android.util.TypedValue;
@@ -31,6 +37,7 @@
 import android.widget.RemoteViews;
 
 import java.text.NumberFormat;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -41,30 +48,38 @@
 
     static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
     static final int MAX_MEDIA_BUTTONS = 5;
+    private static final int MAX_ACTION_BUTTONS = 3;
 
-    public static <T extends NotificationCompatBase.Action> void overrideContentView(
+    public static <T extends NotificationCompatBase.Action> RemoteViews overrideContentViewMedia(
             NotificationBuilderWithBuilderAccessor builder,
             Context context, CharSequence contentTitle, CharSequence contentText,
             CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
-            boolean useChronometer, long when, List<T> actions, int[] actionsToShowInCompact,
-            boolean showCancelButton, PendingIntent cancelButtonIntent) {
-        RemoteViews views = generateContentView(context, contentTitle, contentText, contentInfo,
-                number, largeIcon, subText, useChronometer, when, actions, actionsToShowInCompact,
-                showCancelButton, cancelButtonIntent);
+            boolean useChronometer, long when, int priority, List<T> actions,
+            int[] actionsToShowInCompact, boolean showCancelButton,
+            PendingIntent cancelButtonIntent, boolean isDecoratedCustomView) {
+        RemoteViews views = generateContentViewMedia(context, contentTitle, contentText, contentInfo,
+                number, largeIcon, subText, useChronometer, when, priority, actions,
+                actionsToShowInCompact, showCancelButton, cancelButtonIntent,
+                isDecoratedCustomView);
         builder.getBuilder().setContent(views);
         if (showCancelButton) {
             builder.getBuilder().setOngoing(true);
         }
+        return views;
     }
 
-    private static <T extends NotificationCompatBase.Action> RemoteViews generateContentView(
+    private static <T extends NotificationCompatBase.Action> RemoteViews generateContentViewMedia(
             Context context, CharSequence contentTitle, CharSequence contentText,
             CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
-            boolean useChronometer, long when, List<T> actions, int[] actionsToShowInCompact,
-            boolean showCancelButton, PendingIntent cancelButtonIntent) {
+            boolean useChronometer, long when, int priority, List<T> actions,
+            int[] actionsToShowInCompact, boolean showCancelButton,
+            PendingIntent cancelButtonIntent, boolean isDecoratedCustomView) {
         RemoteViews view = applyStandardTemplate(context, contentTitle, contentText, contentInfo,
-                number, largeIcon, subText, useChronometer, when,
-                R.layout.notification_template_media, true /* fitIn1U */);
+                number, 0 /* smallIcon */, largeIcon, subText, useChronometer, when, priority,
+                0 /* color is unused on media */,
+                isDecoratedCustomView ? R.layout.notification_template_media_custom
+                        : R.layout.notification_template_media,
+                true /* fitIn1U */);
 
         final int numActions = actions.size();
         final int N = actionsToShowInCompact == null
@@ -97,28 +112,31 @@
         return view;
     }
 
-    public static <T extends NotificationCompatBase.Action> void overrideBigContentView(
+    public static <T extends NotificationCompatBase.Action> void overrideMediaBigContentView(
             Notification n, Context context, CharSequence contentTitle, CharSequence contentText,
             CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
-            boolean useChronometer, long when, List<T> actions, boolean showCancelButton,
-            PendingIntent cancelButtonIntent) {
-        n.bigContentView = generateBigContentView(context, contentTitle, contentText, contentInfo,
-                number, largeIcon, subText, useChronometer, when, actions, showCancelButton,
-                cancelButtonIntent);
+            boolean useChronometer, long when, int priority, int color, List<T> actions,
+            boolean showCancelButton, PendingIntent cancelButtonIntent,
+            boolean decoratedCustomView) {
+        n.bigContentView = generateMediaBigView(context, contentTitle, contentText, contentInfo,
+                number, largeIcon, subText, useChronometer, when, priority, color,
+                actions, showCancelButton, cancelButtonIntent, decoratedCustomView);
         if (showCancelButton) {
             n.flags |= Notification.FLAG_ONGOING_EVENT;
         }
     }
 
-    private static <T extends NotificationCompatBase.Action> RemoteViews generateBigContentView(
+    public static <T extends NotificationCompatBase.Action> RemoteViews generateMediaBigView(
             Context context, CharSequence contentTitle, CharSequence contentText,
             CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
-            boolean useChronometer, long when, List<T> actions, boolean showCancelButton,
-            PendingIntent cancelButtonIntent) {
+            boolean useChronometer, long when, int priority, int color, List<T> actions,
+            boolean showCancelButton, PendingIntent cancelButtonIntent,
+            boolean decoratedCustomView) {
         final int actionCount = Math.min(actions.size(), MAX_MEDIA_BUTTONS);
         RemoteViews big = applyStandardTemplate(context, contentTitle, contentText, contentInfo,
-                number, largeIcon, subText, useChronometer, when,
-                getBigLayoutResource(actionCount), false /* fitIn1U */);
+                number, 0 /* smallIcon */, largeIcon, subText, useChronometer, when, priority,
+                color,  /* fitIn1U */getBigMediaLayoutResource(decoratedCustomView, actionCount),
+                false);
 
         big.removeAllViews(R.id.media_actions);
         if (actionCount > 0) {
@@ -153,29 +171,162 @@
         return button;
     }
 
-    private static int getBigLayoutResource(int actionCount) {
+    private static int getBigMediaLayoutResource(boolean decoratedCustomView, int actionCount) {
         if (actionCount <= 3) {
-            return R.layout.notification_template_big_media_narrow;
+            return decoratedCustomView
+                    ? R.layout.notification_template_big_media_narrow_custom
+                    : R.layout.notification_template_big_media_narrow;
         } else {
-            return R.layout.notification_template_big_media;
+            return decoratedCustomView
+                    ? R.layout.notification_template_big_media_custom
+                    : R.layout.notification_template_big_media;
         }
     }
 
-    private static RemoteViews applyStandardTemplate(Context context,
+    public static RemoteViews applyStandardTemplateWithActions(Context context,
             CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
-            int number, Bitmap largeIcon, CharSequence subText, boolean useChronometer, long when,
-            int resId, boolean fitIn1U) {
+            int number, int smallIcon, Bitmap largeIcon, CharSequence subText,
+            boolean useChronometer, long when, int priority, int color, int resId, boolean fitIn1U,
+            ArrayList<NotificationCompat.Action> actions) {
+        RemoteViews remoteViews = applyStandardTemplate(context, contentTitle, contentText,
+                contentInfo, number, smallIcon, largeIcon, subText, useChronometer, when, priority,
+                color, resId, fitIn1U);
+        remoteViews.removeAllViews(R.id.actions);
+        boolean actionsVisible = false;
+        if (actions != null) {
+            int N = actions.size();
+            if (N > 0) {
+                actionsVisible = true;
+                if (N > MAX_ACTION_BUTTONS) N = MAX_ACTION_BUTTONS;
+                for (int i = 0; i < N; i++) {
+                    final RemoteViews button = generateActionButton(context, actions.get(i));
+                    remoteViews.addView(R.id.actions, button);
+                }
+            }
+        }
+        int actionVisibility = actionsVisible ? View.VISIBLE : View.GONE;
+        remoteViews.setViewVisibility(R.id.actions, actionVisibility);
+        remoteViews.setViewVisibility(R.id.action_divider, actionVisibility);
+        return remoteViews;
+    }
+
+    private static RemoteViews generateActionButton(Context context,
+            NotificationCompat.Action action) {
+        final boolean tombstone = (action.actionIntent == null);
+        RemoteViews button =  new RemoteViews(context.getPackageName(),
+                tombstone ? getActionTombstoneLayoutResource()
+                        : getActionLayoutResource());
+        button.setImageViewBitmap(R.id.action_image,
+                createColoredBitmap(context, action.getIcon(),
+                        context.getResources().getColor(R.color.notification_action_color_filter)));
+        button.setTextViewText(R.id.action_text, action.title);
+        if (!tombstone) {
+            button.setOnClickPendingIntent(R.id.action_container, action.actionIntent);
+        }
+        button.setContentDescription(R.id.action_container, action.title);
+        return button;
+    }
+
+    private static Bitmap createColoredBitmap(Context context, int iconId, int color) {
+        return createColoredBitmap(context, iconId, color, 0);
+    }
+
+    private static Bitmap createColoredBitmap(Context context, int iconId, int color, int size) {
+        Drawable drawable = context.getResources().getDrawable(iconId);
+        int width = size == 0 ? drawable.getIntrinsicWidth() : size;
+        int height = size == 0 ? drawable.getIntrinsicHeight() : size;
+        Bitmap resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        drawable.setBounds(0, 0, width, height);
+        if (color != 0) {
+            drawable.mutate().setColorFilter(
+                    new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
+        }
+        Canvas canvas = new Canvas(resultBitmap);
+        drawable.draw(canvas);
+        return resultBitmap;
+    }
+
+    private static int getActionLayoutResource() {
+        return R.layout.notification_action;
+    }
+
+    private static int getActionTombstoneLayoutResource() {
+        return R.layout.notification_action_tombstone;
+    }
+
+    public static RemoteViews applyStandardTemplate(Context context,
+            CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
+            int number, int smallIcon, Bitmap largeIcon, CharSequence subText,
+            boolean useChronometer, long when, int priority, int color, int resId,
+            boolean fitIn1U) {
+        Resources res = context.getResources();
         RemoteViews contentView = new RemoteViews(context.getPackageName(), resId);
         boolean showLine3 = false;
         boolean showLine2 = false;
 
-        // On versions before Jellybean, the large icon was shown by SystemUI, so we need to hide
-        // it here.
-        if (largeIcon != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+        boolean minPriority = priority < NotificationCompat.PRIORITY_LOW;
+        boolean afterJellyBean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+        boolean afterLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+        if (afterJellyBean && !afterLollipop) {
+            // lets color the backgrounds
+            if (minPriority) {
+                contentView.setInt(R.id.notification_background,
+                        "setBackgroundResource", R.drawable.notification_bg_low);
+                contentView.setInt(R.id.icon,
+                        "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
+            } else {
+                contentView.setInt(R.id.notification_background,
+                        "setBackgroundResource", R.drawable.notification_bg);
+                contentView.setInt(R.id.icon,
+                        "setBackgroundResource", R.drawable.notification_template_icon_bg);
+            }
+        }
+
+        if (largeIcon != null) {
+            // On versions before Jellybean, the large icon was shown by SystemUI, so we need to hide
+            // it here.
+            if (afterJellyBean) {
+                contentView.setViewVisibility(R.id.icon, View.VISIBLE);
+                contentView.setImageViewBitmap(R.id.icon, largeIcon);
+            } else {
+                contentView.setViewVisibility(R.id.icon, View.GONE);
+            }
+            if (smallIcon != 0) {
+                int backgroundSize = res.getDimensionPixelSize(
+                        R.dimen.notification_right_icon_size);
+                int iconSize = backgroundSize - res.getDimensionPixelSize(
+                        R.dimen.notification_small_icon_background_padding) * 2;
+                if (afterLollipop) {
+                    Bitmap smallBit = createIconWithBackground(context,
+                            smallIcon,
+                            backgroundSize,
+                            iconSize,
+                            color);
+                    contentView.setImageViewBitmap(R.id.right_icon, smallBit);
+                } else {
+                    contentView.setImageViewBitmap(R.id.right_icon,
+                            createColoredBitmap(context, smallIcon, Color.WHITE));
+                }
+                contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
+            }
+        } else if (smallIcon != 0) { // small icon at left
             contentView.setViewVisibility(R.id.icon, View.VISIBLE);
-            contentView.setImageViewBitmap(R.id.icon, largeIcon);
-        } else {
-            contentView.setViewVisibility(R.id.icon, View.GONE);
+            if (afterLollipop) {
+                int backgroundSize = res.getDimensionPixelSize(
+                        R.dimen.notification_large_icon_width)
+                        - res.getDimensionPixelSize(R.dimen.notification_big_circle_margin);
+                int iconSize = res.getDimensionPixelSize(
+                        R.dimen.notification_small_icon_size_as_large);
+                Bitmap smallBit = createIconWithBackground(context,
+                        smallIcon,
+                        backgroundSize,
+                        iconSize,
+                        color);
+                contentView.setImageViewBitmap(R.id.icon, smallBit);
+            } else {
+                contentView.setImageViewBitmap(R.id.icon,
+                        createColoredBitmap(context, smallIcon, Color.WHITE));
+            }
         }
         if (contentTitle != null) {
             contentView.setTextViewText(R.id.title, contentTitle);
@@ -184,15 +335,18 @@
             contentView.setTextViewText(R.id.text, contentText);
             showLine3 = true;
         }
+        // If there is a large icon we have a right side
+        boolean hasRightSide = !afterLollipop && largeIcon != null;
         if (contentInfo != null) {
             contentView.setTextViewText(R.id.info, contentInfo);
             contentView.setViewVisibility(R.id.info, View.VISIBLE);
             showLine3 = true;
+            hasRightSide = true;
         } else if (number > 0) {
-            final int tooBig = context.getResources().getInteger(
+            final int tooBig = res.getInteger(
                     R.integer.status_bar_notification_info_maxnum);
             if (number > tooBig) {
-                contentView.setTextViewText(R.id.info, context.getResources().getString(
+                contentView.setTextViewText(R.id.info, ((Resources) res).getString(
                         R.string.status_bar_notification_info_overflow));
             } else {
                 NumberFormat f = NumberFormat.getIntegerInstance();
@@ -200,12 +354,13 @@
             }
             contentView.setViewVisibility(R.id.info, View.VISIBLE);
             showLine3 = true;
+            hasRightSide = true;
         } else {
             contentView.setViewVisibility(R.id.info, View.GONE);
         }
 
         // Need to show three lines? Only allow on Jellybean+
-        if (subText != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+        if (subText != null && afterJellyBean) {
             contentView.setTextViewText(R.id.text, subText);
             if (contentText != null) {
                 contentView.setTextViewText(R.id.text2, contentText);
@@ -217,10 +372,9 @@
         }
 
         // RemoteViews.setViewPadding and RemoteViews.setTextViewTextSize is not available on ICS-
-        if (showLine2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+        if (showLine2 && afterJellyBean) {
             if (fitIn1U) {
                 // need to shrink all the type to make sure everything fits
-                final Resources res = context.getResources();
                 final float subTextSize = res.getDimensionPixelSize(
                         R.dimen.notification_subtext_size);
                 contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
@@ -230,7 +384,7 @@
         }
 
         if (when != 0) {
-            if (useChronometer) {
+            if (useChronometer && afterJellyBean) {
                 contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
                 contentView.setLong(R.id.chronometer, "setBase",
                         when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
@@ -239,8 +393,61 @@
                 contentView.setViewVisibility(R.id.time, View.VISIBLE);
                 contentView.setLong(R.id.time, "setTime", when);
             }
+            hasRightSide = true;
         }
+        contentView.setViewVisibility(R.id.right_side, hasRightSide ? View.VISIBLE : View.GONE);
         contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
         return contentView;
     }
+
+    public static Bitmap createIconWithBackground(Context ctx, int iconId, int size, int iconSize,
+            int color) {
+        Bitmap coloredBitmap = createColoredBitmap(ctx, R.drawable.notification_icon_background,
+                        color == NotificationCompat.COLOR_DEFAULT ? 0 : color, size);
+        Canvas canvas = new Canvas(coloredBitmap);
+        Drawable icon = ctx.getResources().getDrawable(iconId).mutate();
+        icon.setFilterBitmap(true);
+        int inset = (size - iconSize) / 2;
+        icon.setBounds(inset, inset, iconSize + inset, iconSize + inset);
+        icon.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP));
+        icon.draw(canvas);
+        return coloredBitmap;
+    }
+
+    public static void buildIntoRemoteViews(Context ctx, RemoteViews outerView,
+            RemoteViews innerView) {
+        // this needs to be done fore the other calls, since otherwise we might hide the wrong
+        // things if our ids collide.
+        hideNormalContent(outerView);
+        outerView.removeAllViews(R.id.notification_main_column);
+        outerView.addView(R.id.notification_main_column, innerView.clone());
+        outerView.setViewVisibility(R.id.notification_main_column, View.VISIBLE);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // Adjust padding depending on font size.
+            outerView.setViewPadding(R.id.notification_main_column_container,
+                    0, calculateTopPadding(ctx), 0, 0);
+        }
+    }
+
+    private static void hideNormalContent(RemoteViews outerView) {
+        outerView.setViewVisibility(R.id.title, View.GONE);
+        outerView.setViewVisibility(R.id.text2, View.GONE);
+        outerView.setViewVisibility(R.id.text, View.GONE);
+    }
+
+    public static int calculateTopPadding(Context ctx) {
+        int padding = ctx.getResources().getDimensionPixelSize(R.dimen.notification_top_pad);
+        int largePadding = ctx.getResources().getDimensionPixelSize(
+                R.dimen.notification_top_pad_large_text);
+        float fontScale = ctx.getResources().getConfiguration().fontScale;
+        float largeFactor = (constrain(fontScale, 1.0f, 1.3f) - 1f) / (1.3f - 1f);
+
+        // Linearly interpolate the padding between large and normal with the font scale ranging
+        // from 1f to LARGE_TEXT_SCALE
+        return Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
+    }
+
+    public static float constrain(float amount, float low, float high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java
new file mode 100644
index 0000000..cf8d128
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.app;
+
+import android.app.Notification;
+import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
+
+class NotificationCompatImplJellybean {
+
+    public static void addBigTextStyle(NotificationBuilderWithBuilderAccessor b,
+            CharSequence bigText) {
+        Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle(b.getBuilder());
+        bigTextStyle.bigText(bigText);
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
index 2d6def1..48bbbdc 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.widget.TintTypedArray;
 import android.util.AttributeSet;
@@ -84,7 +85,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        setBackgroundDrawable(mBackground);
+        ViewCompat.setBackground(this, mBackground);
 
         mTitleView = (TextView) findViewById(R.id.title);
         if (mTextAppearance != -1) {
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
index 00e7d4c..bb94460 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
@@ -20,6 +20,7 @@
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.view.ActionMode;
 import android.util.AttributeSet;
@@ -57,7 +58,7 @@
         final Drawable bg = Build.VERSION.SDK_INT >= 21
                 ? new ActionBarBackgroundDrawableV21(this)
                 : new ActionBarBackgroundDrawable(this);
-        setBackgroundDrawable(bg);
+        ViewCompat.setBackground(this, bg);
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.ActionBar);
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
index 4f45c2a..52391d1 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.os.Build;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.view.ActionMode;
 import android.support.v7.view.menu.MenuBuilder;
@@ -62,8 +63,7 @@
 
         final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
                 R.styleable.ActionMode, defStyle, 0);
-        setBackgroundDrawable(a.getDrawable(
-                R.styleable.ActionMode_background));
+        ViewCompat.setBackground(this, a.getDrawable(R.styleable.ActionMode_background));
         mTitleStyleRes = a.getResourceId(
                 R.styleable.ActionMode_titleTextStyle, 0);
         mSubtitleStyleRes = a.getResourceId(
@@ -179,7 +179,7 @@
                 LayoutParams.MATCH_PARENT);
         menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
         mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
-        mMenuView.setBackgroundDrawable(null);
+        ViewCompat.setBackground(mMenuView, null);
         addView(mMenuView, layoutParams);
     }
 
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index fe4b0f6..fb94cd9 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -85,7 +85,8 @@
 
     private static void installDefaultInflateDelegates(@NonNull AppCompatDrawableManager manager) {
         final int sdk = Build.VERSION.SDK_INT;
-        if (sdk < 23) {
+        // This sdk version check will affect src:appCompat code path.
+        if (sdk < 24) {
             // We only want to use the automatic VectorDrawableCompat handling where it's
             // needed: on devices running before Lollipop
             manager.addDelegate("vector", new VdcInflateDelegate());
diff --git a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
index 7d53b93..3e4d063 100644
--- a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
+++ b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
@@ -16,13 +16,16 @@
 
 package android.support.v7.widget;
 
+import android.os.Build;
 import android.os.SystemClock;
 import android.support.v4.view.MotionEventCompat;
 import android.support.v7.view.menu.ShowableListMenu;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 
 
 /**
@@ -31,6 +34,7 @@
  * @hide
  */
 public abstract class ForwardingListener implements View.OnTouchListener {
+
     /** Scaled touch slop, used for detecting movement outside bounds. */
     private final float mScaledTouchSlop;
 
@@ -62,12 +66,48 @@
 
     public ForwardingListener(View src) {
         mSrc = src;
+        src.setLongClickable(true);
+
+        if (Build.VERSION.SDK_INT >= 12) {
+            addDetachListenerApi12(src);
+        } else {
+            addDetachListenerBase(src);
+        }
+
         mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
         mTapTimeout = ViewConfiguration.getTapTimeout();
+
         // Use a medium-press timeout. Halfway between tap and long-press.
         mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
     }
 
+    private void addDetachListenerApi12(View src) {
+        src.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+            @Override
+            public void onViewAttachedToWindow(View v) {}
+
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+                onDetachedFromWindow();
+            }
+        });
+    }
+
+    private void addDetachListenerBase(View src) {
+        src.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+            boolean mIsAttached = mSrc.isAttachedToWindow();
+
+            @Override
+            public void onGlobalLayout() {
+                final boolean wasAttached = mIsAttached;
+                mIsAttached = mSrc.isAttachedToWindow();
+                if (wasAttached && !mIsAttached) {
+                    onDetachedFromWindow();
+                }
+            }
+        });
+    }
+
     /**
      * Returns the popup to which this listener is forwarding events.
      * <p>
@@ -103,6 +143,15 @@
         return forwarding || wasForwarding;
     }
 
+    private void onDetachedFromWindow() {
+        mForwarding = false;
+        mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+        if (mDisallowIntercept != null) {
+            mSrc.removeCallbacks(mDisallowIntercept);
+        }
+    }
+
     /**
      * Called when forwarding would like to start.
      * <p>
diff --git a/v7/appcompat/src/android/support/v7/widget/SearchView.java b/v7/appcompat/src/android/support/v7/widget/SearchView.java
index bb703cc..d823324 100644
--- a/v7/appcompat/src/android/support/v7/widget/SearchView.java
+++ b/v7/appcompat/src/android/support/v7/widget/SearchView.java
@@ -46,6 +46,7 @@
 import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.KeyEventCompat;
+import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.CursorAdapter;
 import android.support.v7.appcompat.R;
 import android.support.v7.view.CollapsibleActionView;
@@ -313,8 +314,10 @@
         mCollapsedIcon = (ImageView) findViewById(R.id.search_mag_icon);
 
         // Set up icons and backgrounds.
-        mSearchPlate.setBackgroundDrawable(a.getDrawable(R.styleable.SearchView_queryBackground));
-        mSubmitArea.setBackgroundDrawable(a.getDrawable(R.styleable.SearchView_submitBackground));
+        ViewCompat.setBackground(mSearchPlate,
+                a.getDrawable(R.styleable.SearchView_queryBackground));
+        ViewCompat.setBackground(mSubmitArea,
+                a.getDrawable(R.styleable.SearchView_submitBackground));
         mSearchButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
         mGoButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_goIcon));
         mCloseButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_closeIcon));
diff --git a/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
index 283151b..040fc90 100644
--- a/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
@@ -643,8 +643,7 @@
 
     @Override
     public void setBackgroundDrawable(Drawable d) {
-        //noinspection deprecation
-        mToolbar.setBackgroundDrawable(d);
+        ViewCompat.setBackground(mToolbar, d);
     }
 
     @Override
diff --git a/v7/appcompat/tests/res/layout/toolbar_decor_content.xml b/v7/appcompat/tests/res/layout/toolbar_decor_content.xml
index 91d93ca..db9935d 100644
--- a/v7/appcompat/tests/res/layout/toolbar_decor_content.xml
+++ b/v7/appcompat/tests/res/layout/toolbar_decor_content.xml
@@ -32,7 +32,8 @@
         <EditText
                 android:id="@+id/editText"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
+                android:layout_height="wrap_content"
+                android:imeOptions="flagNoExtractUi"/>
 
     </android.support.v7.custom.FitWindowsContentLayout>
 
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
index 97383c3..9c50144 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
@@ -16,7 +16,10 @@
 
 package android.support.v7.app;
 
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.os.SystemClock;
 import android.support.v7.appcompat.test.R;
@@ -27,10 +30,7 @@
 import android.view.MenuItem;
 import android.view.View;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import org.junit.Test;
 
 public abstract class BaseKeyboardShortcutsTestCase<A extends BaseTestActivity>
         extends BaseInstrumentationTestCase<A> {
@@ -63,66 +63,4 @@
         assertNotNull("Options item selected", selectedItem);
         assertEquals("Correct options item selected", selectedItem.getItemId(), expectedId);
     }
-
-    @Test
-    @SmallTest
-    public void testAccessActionBar() throws Throwable {
-        final BaseTestActivity activity = getActivity();
-
-        final View editText = activity.findViewById(R.id.editText);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                editText.requestFocus();
-            }
-        });
-
-        getInstrumentation().waitForIdleSync();
-        sendControlChar('<');
-        getInstrumentation().waitForIdleSync();
-
-        // Should jump to the action bar after control-<
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertFalse(editText.hasFocus());
-                final View toolbar = activity.findViewById(R.id.toolbar);
-                assertTrue(toolbar.hasFocus());
-            }
-        });
-        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
-        getInstrumentation().waitForIdleSync();
-
-        // Should jump to the first view again.
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(editText.hasFocus());
-            }
-        });
-        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
-        getInstrumentation().waitForIdleSync();
-
-        // Now it shouldn't go up to action bar -- it doesn't allow taking focus once left
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(editText.hasFocus());
-            }
-        });
-    }
-
-    private void sendControlChar(char key) throws Throwable {
-        KeyEvent tempEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
-        KeyCharacterMap map = tempEvent.getKeyCharacterMap();
-        KeyEvent[] events = map.getEvents(new char[] {key});
-        for (int i = 0; i < events.length; i++) {
-            long time = SystemClock.uptimeMillis();
-            KeyEvent event = events[i];
-            KeyEvent controlKey = new KeyEvent(time, time, event.getAction(), event.getKeyCode(),
-                    event.getRepeatCount(), event.getMetaState() | KeyEvent.META_CTRL_ON);
-            getInstrumentation().sendKeySync(controlKey);
-        }
-    }
-
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
index 2381821..a165d53 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
@@ -20,10 +20,12 @@
 
 import android.app.Dialog;
 import android.os.Bundle;
+import android.test.suitebuilder.annotation.MediumTest;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+@MediumTest
 public class DialogTestCase extends BaseInstrumentationTestCase<WindowDecorActionBarActivity> {
 
     public DialogTestCase() {
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
index 16c37a2..a27b20b 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
@@ -16,9 +16,74 @@
 
 package android.support.v7.app;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.support.v7.testutils.BaseTestActivity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+
+import org.junit.Test;
+
 public class KeyboardShortcutsTestCaseWithToolbar
         extends BaseKeyboardShortcutsTestCase<ToolbarActionBarActivity> {
     public KeyboardShortcutsTestCaseWithToolbar() {
         super(ToolbarActionBarActivity.class);
     }
+
+    @Test
+    @SmallTest
+    public void testAccessActionBar() throws Throwable {
+        final BaseTestActivity activity = getActivity();
+
+        final View editText = activity.findViewById(android.support.v7.appcompat.test.R.id.editText);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                editText.requestFocus();
+            }
+        });
+
+        getInstrumentation().waitForIdleSync();
+        sendControlChar('<');
+        getInstrumentation().waitForIdleSync();
+
+        // Should jump to the action bar after control-<
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(editText.hasFocus());
+                final View toolbar = activity.findViewById(android.support.v7.appcompat.test.R.id.toolbar);
+                assertTrue(toolbar.hasFocus());
+            }
+        });
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        getInstrumentation().waitForIdleSync();
+
+        // Should jump to the first view again.
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(editText.hasFocus());
+            }
+        });
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
+        getInstrumentation().waitForIdleSync();
+    }
+
+    private void sendControlChar(char key) throws Throwable {
+        KeyEvent tempEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
+        KeyCharacterMap map = tempEvent.getKeyCharacterMap();
+        KeyEvent[] events = map.getEvents(new char[] {key});
+        for (int i = 0; i < events.length; i++) {
+            long time = SystemClock.uptimeMillis();
+            KeyEvent event = events[i];
+            KeyEvent controlKey = new KeyEvent(time, time, event.getAction(), event.getKeyCode(),
+                    event.getRepeatCount(), event.getMetaState() | KeyEvent.META_CTRL_ON);
+            getInstrumentation().sendKeySync(controlKey);
+        }
+    }
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
index 55d0d39..bb712d1 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
@@ -23,6 +23,8 @@
 import android.support.test.espresso.ViewInteraction;
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.TestUtilsMatchers;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.ImageView;
 
 import org.junit.Test;
@@ -31,6 +33,7 @@
  * In addition to all tinting-related tests done by the base class, this class provides
  * tests specific to {@link AppCompatImageView} class.
  */
+@SmallTest
 public class AppCompatImageViewTest
         extends AppCompatBaseViewTest<AppCompatImageViewActivity, AppCompatImageView> {
     public AppCompatImageViewTest() {
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
index 09590bd..ba27a88 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
@@ -278,7 +278,8 @@
         // Allow for off-by-one mismatch in anchoring
         assertEquals("Anchoring X", anchorOnScreenXY[0] + popupInWindowXY[0],
                 popupOnScreenXY[0], 1);
-        assertEquals("Anchoring Y", anchorOnScreenXY[1] + popupInWindowXY[1] + mButton.getHeight(),
+        assertEquals("Anchoring Y",
+                anchorOnScreenXY[1] + popupInWindowXY[1] + mButton.getHeight() - popupPadding.top,
                 popupOnScreenXY[1], 1);
     }
 
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java b/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java
index 81cac57..673a6aa 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java
@@ -23,9 +23,11 @@
 import android.graphics.drawable.Drawable;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.app.BaseInstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import org.junit.Test;
 
+@SmallTest
 public class TintResourcesTest extends BaseInstrumentationTestCase<AppCompatActivity> {
 
     public TintResourcesTest() {
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
index 9811194..444ffc2 100644
--- a/v7/mediarouter/res/values-af/strings.xml
+++ b/v7/mediarouter/res/values-af/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Stelsel"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Toestelle"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knoppie"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Uitsaai-knoppie. Ontkoppel"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Uitsaai-knoppie. Koppel tans"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Uitsaai-knoppie. Gekoppel"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Saai uit na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Vind tans toestelle"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ontkoppel"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Vou uit"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Vou in"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumkunswerk"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeglyer"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media is gekies nie"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen inligting beskikbaar nie"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Saai tans skerm uit"</string>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
index 6f7931d..96a2c09 100644
--- a/v7/mediarouter/res/values-am/strings.xml
+++ b/v7/mediarouter/res/values-am/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ስርዓት"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"መሣሪያዎች"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"የCast አዝራር"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast አዝራር። ግንኙነት ተቋርጧል"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast አዝራር በማገናኘት ላይ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast አዝራር። ተገናኝቷል"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast አድርግ ወደ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"መሣሪያዎችን በማግኘት ላይ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ግንኙነት አቋርጥ"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"አስፋ"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ሰብስብ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"የአልበም ስነ-ጥበብ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ተንሸራታች የድምፅ መቆጣጠሪያ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ምንም ማህደረመረጃ አልተመረጠም"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ምንም መረጃ አይገኝም"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ማያ ገጽን በመውሰድ ላይ"</string>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
index 29cab47..3caf4b6 100644
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ b/v7/mediarouter/res/values-ar/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"زر الإرسال"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"زر الإرسال. تم قطع الاتصال"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"زر الإرسال. جارٍ الاتصال"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"زر الإرسال. تم الاتصال"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"إرسال إلى"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"جارٍ البحث عن أجهزة"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع الاتصال"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"توسيع"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"تصغير"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"صورة الألبوم"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"شريط تمرير مستوى الصوت"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"لم يتم اختيار أية وسائط"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"لا تتوفر أية معلومات"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"جارٍ إرسال الشاشة"</string>
diff --git a/v7/mediarouter/res/values-az-rAZ/strings.xml b/v7/mediarouter/res/values-az-rAZ/strings.xml
index 765520e..31574c3 100644
--- a/v7/mediarouter/res/values-az-rAZ/strings.xml
+++ b/v7/mediarouter/res/values-az-rAZ/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Yayım düyməsi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayım düyməsi. Bağlantı kəsildi"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayım düyməsi. Qoşulur"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayım düyməsi. Qoşuldu"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Bura yayımlayın"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar axtarılır"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantını kəsin"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişləndirin"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yığcamlaşdırın"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albom incəsənəti"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Səs hərmi diyircəyi"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Heç bir media seçilməyib"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Əlçatan məlumat yoxdur"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayımlanır"</string>
diff --git a/v7/mediarouter/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
index 6c32754..8075d2e 100644
--- a/v7/mediarouter/res/values-b+sr+Latn/strings.xml
+++ b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Dugme Prebaci"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme Prebaci. Veza je prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme Prebaci. Povezuje se"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme Prebaci. Povezan je"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Pronalaženje uređaja"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nema izabranih medija"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nisu dostupne nikakve informacije"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
diff --git a/v7/mediarouter/res/values-be-rBY/strings.xml b/v7/mediarouter/res/values-be-rBY/strings.xml
index de52c06..75c24d5 100644
--- a/v7/mediarouter/res/values-be-rBY/strings.xml
+++ b/v7/mediarouter/res/values-be-rBY/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Сістэма"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Прылады"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляцыі"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляцыі. Адключана"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляцыі. Ідзе падключэнне"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляцыі. Падключана"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Трансляваць на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Пошук прылад"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Адлучыць"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгарнуць"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згарнуць"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Вокладка альбома"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Паўзунок гучнасці"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медыяфайл не выбраны"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Інфармацыя адсутнічае"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Экран трансляцыі"</string>
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
index 036b31f..d756d6c 100644
--- a/v7/mediarouter/res/values-bg/strings.xml
+++ b/v7/mediarouter/res/values-bg/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Бутон за предаване"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Бутон за предаване. Връзката е прекратена"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Бутон за предаване. Свързва се"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Бутон за предаване. Установена е връзка"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Предаване към"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Търсят се устройства"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Прекратяване на връзката"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгъване"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свиване"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Обложка на албума"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Плъзгач за силата на звука"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Няма избрана мултимедия"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Няма налична информация"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Екранът се предава"</string>
diff --git a/v7/mediarouter/res/values-bn-rBD/strings.xml b/v7/mediarouter/res/values-bn-rBD/strings.xml
index 0e3e491..b94b9af 100644
--- a/v7/mediarouter/res/values-bn-rBD/strings.xml
+++ b/v7/mediarouter/res/values-bn-rBD/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"সিস্টেম"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ডিভাইসগুলি"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"কাস্ট করার বোতাম"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"কাস্ট করার বোতাম৷ সংযোগ বিচ্ছিন্ন হয়েছে"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"কাস্ট করার বোতাম৷ সংযোগ করা হচ্ছে"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"কাস্ট করার বোতাম৷ সংযুক্ত হয়েছে"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"এতে কাস্ট করুন"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ডিভাইসগুলিকে খোঁজা হচ্ছে"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"সংযোগ বিচ্ছিন্ন করুন"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"প্রসারিত করুন"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"সঙ্কুচিত করুন"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"অ্যালবাম শৈলি"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ভলিউম স্লাইডার"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"কোনো মিডিয়া নির্বাচন করা হয়নি"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"কোনো তথ্য উপলব্ধ নেই"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"স্ক্রীন কাস্ট করা হচ্ছে"</string>
diff --git a/v7/mediarouter/res/values-bs-rBA/strings.xml b/v7/mediarouter/res/values-bs-rBA/strings.xml
index a6894f5..df4e3ef 100644
--- a/v7/mediarouter/res/values-bs-rBA/strings.xml
+++ b/v7/mediarouter/res/values-bs-rBA/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Dugme za prebacivanje"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme za prebacivanje. Veza je prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme za prebacivanje. Povezivanje"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme za prebacivanje. Povezan"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nijedan medij nije odabran"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nema dostupnih informacija"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
index 7fc51f7..400d424 100644
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ b/v7/mediarouter/res/values-ca/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botó d\'emetre"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botó Emet. Desconnectat."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botó Emet. S\'està connectant."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botó Emet. Connectat."</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Emet a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"S\'estan cercant dispositius"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconnecta"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Desplega"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Replega"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Imatge de l\'àlbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control lliscant de volum"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No s\'ha seleccionat cap fitxer multimèdia"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hi ha informació disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emissió de pantalla"</string>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/res/values-cs/strings.xml
index f5a286e..5a29bac 100644
--- a/v7/mediarouter/res/values-cs/strings.xml
+++ b/v7/mediarouter/res/values-cs/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Zařízení"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačítko odesílání"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačítko odesílání. Odpojeno"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačítko odesílání. Připojování"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačítko odesílání. Připojeno"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Odesílat do"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Hledání zařízení"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojit"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbalit"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sbalit"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Obal alba"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posuvník hlasitosti"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nebyla vybrána žádná média"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nejsou k dispozici žádné informace"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Odesílání obsahu obrazovky"</string>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
index 9e5f9a5..f33a4ee 100644
--- a/v7/mediarouter/res/values-da/strings.xml
+++ b/v7/mediarouter/res/values-da/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knap"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knap. Forbindelsen er afbrudt"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knap. Opretter forbindelse"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knap. Tilsluttet"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finder enheder"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Afbryd"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Udvid"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafik"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Lydstyrkeskyder"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Der er ikke valgt nogen medier"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Der er ingen tilgængelige oplysninger"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skærmen castes"</string>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/res/values-de/strings.xml
index 91d764f..13686aa 100644
--- a/v7/mediarouter/res/values-de/strings.xml
+++ b/v7/mediarouter/res/values-de/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Geräte"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-Symbol"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Streaming-Schaltfläche. Nicht verbunden"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Streaming-Schaltfläche. Verbindung wird hergestellt"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Streaming-Schaltfläche. Verbunden"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Streamen auf"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Geräte werden gesucht."</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Verbindung trennen"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Maximieren"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minimieren"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumcover"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Schieberegler für die Lautstärke"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Keine Medien ausgewählt"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Keine Informationen verfügbar"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Bildschirm wird gestreamt."</string>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
index 0a1a62f..3f45621 100644
--- a/v7/mediarouter/res/values-el/strings.xml
+++ b/v7/mediarouter/res/values-el/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Σύστημα"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Συσκευές"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Κουμπί Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Κουμπί μετάδοσης. Αποσυνδέθηκε"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Κουμπί μετάδοση. Σύνδεση σε εξέλιξη"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Κουμπί μετάδοσης. Συνδέθηκε"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Μετάδοση σε"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Εύρεση συσκευών"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Αποσύνδεση"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ανάπτυξη"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Σύμπτυξη"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Εξώφυλλο άλμπουμ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ρυθμιστικό έντασης ήχου"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Δεν έχουν επιλεγεί μέσα"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Δεν υπάρχουν διαθέσιμες πληροφορίες"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Μετάδοση οθόνης"</string>
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rAU/strings.xml
+++ b/v7/mediarouter/res/values-en-rAU/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rGB/strings.xml
+++ b/v7/mediarouter/res/values-en-rGB/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rIN/strings.xml
+++ b/v7/mediarouter/res/values-en-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
index 2318059..90aa823 100644
--- a/v7/mediarouter/res/values-es-rUS/strings.xml
+++ b/v7/mediarouter/res/values-es-rUS/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botón para transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón para transmitir (desconectado)"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón para transmitir (conectando)"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón para transmitir (conectado)"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Imagen del álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante del volumen"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se seleccionó ningún contenido multimedia"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Sin información disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitiendo pantalla"</string>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
index 9f108fe..52a886f 100644
--- a/v7/mediarouter/res/values-es/strings.xml
+++ b/v7/mediarouter/res/values-es/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de enviar"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de enviar. Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de enviar. Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de enviar. Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Enviar a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Portada del álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante de volumen"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se ha seleccionado ningún medio"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hay información disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Enviando pantalla"</string>
diff --git a/v7/mediarouter/res/values-et-rEE/strings.xml b/v7/mediarouter/res/values-et-rEE/strings.xml
index 3fab845..ce1847a 100644
--- a/v7/mediarouter/res/values-et-rEE/strings.xml
+++ b/v7/mediarouter/res/values-et-rEE/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Süsteem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Seadmed"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Ülekandenupp"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Ülekandenupp. Ühendus on katkestatud"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Ülekandenupp. Ühendamine"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Ülekandenupp. Ühendatud"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Ülekandmine seadmesse"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Seadmete otsimine"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkesta ühendus"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laiendamine"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ahendamine"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumi kujundus"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Helitugevuse liugur"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Meediat pole valitud"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Teave puudub"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekraanikuva ülekandmine"</string>
diff --git a/v7/mediarouter/res/values-eu-rES/strings.xml b/v7/mediarouter/res/values-eu-rES/strings.xml
index bae67ed..c03d73b 100644
--- a/v7/mediarouter/res/values-eu-rES/strings.xml
+++ b/v7/mediarouter/res/values-eu-rES/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Igorri botoia"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Igortzeko botoia. Deskonektatuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Igortzeko botoia. Konektatzen"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Igortzeko botoia. Konektatuta"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Igorri hona"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Gailuak bilatzen"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Deskonektatu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zabaldu"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tolestu"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumaren azala"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bolumenaren graduatzailea"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ez da hautatu multimedia-edukirik"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ez dago informaziorik"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Pantaila igortzen"</string>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
index eb34931..7cc9fbc 100644
--- a/v7/mediarouter/res/values-fa/strings.xml
+++ b/v7/mediarouter/res/values-fa/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"سیستم"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"دستگاه‌ها"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"دکمه ارسال محتوا"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"دکمه فرستادن. ارتباط قطع شد"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"دکمه فرستادن. درحال مرتبط‌سازی"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"دکمه فرستادن. مرتبط شد"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ارسال محتوا به"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"پیدا کردن دستگاه‌ها"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع ارتباط"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"بزرگ کردن"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"کوچک کردن"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"عکس روی جلد آلبوم"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"لغزنده میزان صدا"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"رسانه انتخاب نشده است"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"اطلاعات در دسترس نیست"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"درحال فرستادن صفحه"</string>
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
index f37317a..2465802 100644
--- a/v7/mediarouter/res/values-fi/strings.xml
+++ b/v7/mediarouter/res/values-fi/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Järjestelmä"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Laitteet"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-painike"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-painike. Yhteys katkaistu"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-painike. Yhdistetään"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-painike. Yhdistetty"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Suoratoiston kohde"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Etsitään laitteita"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkaise yhteys"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laajenna"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tiivistä"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumin kansikuva"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Äänenvoimakkuuden liukusäädin"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ei valittua mediaa."</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tietoja ei ole saatavilla"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Suoratoistetaan näyttöä"</string>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
index 5719479..fd1ea8c 100644
--- a/v7/mediarouter/res/values-fr-rCA/strings.xml
+++ b/v7/mediarouter/res/values-fr-rCA/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Bouton Diffuser"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Bouton Diffuser. Déconnecté"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Bouton Diffuser. Connexion en cours…"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Bouton Diffuser. Connecté"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Diffuser sur"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Se déconnecter"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de réglage du volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours"</string>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
index 6ce8329..8c96485 100644
--- a/v7/mediarouter/res/values-fr/strings.xml
+++ b/v7/mediarouter/res/values-fr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Icône Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Icône Cast. Déconnecté"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Icône Cast. Connexion…"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Icône Cast. Connecté"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Caster sur"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils en cours…"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Déconnecter"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours…"</string>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl-rES/strings.xml
index c922b68..83489ac 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl-rES/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de emitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de emitir. Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de emitir. Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de emitir. Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Emitir en"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ampliar"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Contraer"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Portada do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control desprazable do volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Non se seleccionaron recursos"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Non hai información dispoñible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emisión de pantalla"</string>
diff --git a/v7/mediarouter/res/values-gu-rIN/strings.xml b/v7/mediarouter/res/values-gu-rIN/strings.xml
index e3be8fc..eb7a9b8 100644
--- a/v7/mediarouter/res/values-gu-rIN/strings.xml
+++ b/v7/mediarouter/res/values-gu-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"સિસ્ટમ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ઉપકરણો"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"કાસ્ટ કરો બટન"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"કાસ્ટ કરો બટન. ડિસ્કનેક્ટ કર્યું"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"કાસ્ટ કરો બટન. કનેક્ટ થઈ રહ્યું છે"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"કાસ્ટ કરો બટન. કનેક્ટ થયું"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"આના પર કાસ્ટ કરો"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ઉપકરણો શોધી રહ્યાં છીએ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ડિસ્કનેક્ટ કરો"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"વિસ્તૃત કરો"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"સંકુચિત કરો"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"આલ્બમ કલા"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"વૉલ્યુમ સ્લાઇડર"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"કોઈ મીડિયા પસંદ કરેલ નથી"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"કોઈ માહિતી ઉપલબ્ધ નથી"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"સ્ક્રીનને કાસ્ટ કરી રહ્યાં છે"</string>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index 9d0650b..e74967e 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिवाइस"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट करें बटन"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट करें बटन. डिस्कनेक्ट है"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट करें बटन. कनेक्ट हो रहा है"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट करें बटन. कनेक्ट है"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"इस पर कास्‍ट करें"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"डिवाइस ढूंढ रहा है"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्कनेक्ट करें"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करें"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त करें"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"वॉल्यूम स्लाइडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कोई मीडिया चयनित नहीं है"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोई जानकारी उपलब्‍ध नहीं"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्ट हो रही है"</string>
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
index 371088b..f50d748 100644
--- a/v7/mediarouter/res/values-hr/strings.xml
+++ b/v7/mediarouter/res/values-hr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sustav"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za emitiranje"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za emitiranje. Veza prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za emitiranje. Povezivanje"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za emitiranje. Povezan"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Emitiranje na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširivanje"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sažimanje"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za glasnoću"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nije odabran nijedan medij"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacije nisu dostupne"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emitiranje zaslona"</string>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
index a3d6990..6420985 100644
--- a/v7/mediarouter/res/values-hu/strings.xml
+++ b/v7/mediarouter/res/values-hu/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Rendszer"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Eszközök"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Átküldés gomb"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Átküldés gomb. Kapcsolat bontva"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Átküldés gomb. Csatlakozás"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Átküldés gomb. Csatlakoztatva"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Átküldés ide"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Eszközök keresése"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Leválasztás"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kibontás"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Összecsukás"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Lemezborító"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hangerőszabályzó"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nincs média kiválasztva"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nincs információ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Képernyőtartalom átküldése"</string>
diff --git a/v7/mediarouter/res/values-hy-rAM/strings.xml b/v7/mediarouter/res/values-hy-rAM/strings.xml
index a8c1cf3..6e46af8 100644
--- a/v7/mediarouter/res/values-hy-rAM/strings.xml
+++ b/v7/mediarouter/res/values-hy-rAM/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Համակարգ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Սարքեր"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Հեռարձակման կոճակ"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Հեռարձակման կոճակ: Սարքն անջատված է"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Հեռարձակման կոճակ: Սարքը կապակցվում է"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Հեռարձակման կոճակ: Սարքը կապակցված է"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Ընտրեք սարքը"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Սարքերի որոնում"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Անջատել"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ընդարձակել"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Կոծկել"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Ալբոմի շապիկ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ձայնի ուժգնության կարգավորիչ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Մեդիա ֆայլեր չեն ընտրվել"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Տեղեկությունները հասանելի չեն"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Էկրանը հեռարձակվում է"</string>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index 4bc0852..43e0c62 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Tombol transmisi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tombol transmisi. Terputus"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tombol transmisi. Menghubungkan"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tombol transmisi. Terhubung"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmisikan ke"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Sampul album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bilah geser volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tidak ada media yang dipilih"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tidak ada info yang tersedia"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmisi layar"</string>
diff --git a/v7/mediarouter/res/values-is-rIS/strings.xml b/v7/mediarouter/res/values-is-rIS/strings.xml
index 08e41e6..53de253 100644
--- a/v7/mediarouter/res/values-is-rIS/strings.xml
+++ b/v7/mediarouter/res/values-is-rIS/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Kerfi"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Tæki"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Útsendingarhnappur"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Útsendingarhnappur. Aftengt"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Útsendingarhnappur. Tengist"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Útsendingarhnappur. Tengt"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Senda út í"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Leitað að tækjum"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Aftengjast"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Stækka"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minnka"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Plötuumslag"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hljóðstyrkssleði"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Enginn miðill valinn"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Engar upplýsingar í boði"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skjár sendur út"</string>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
index 87b570c..df6bbfe 100644
--- a/v7/mediarouter/res/values-it/strings.xml
+++ b/v7/mediarouter/res/values-it/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivi"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Pulsante Trasmetti"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Pulsante Trasmetti. Disconnesso"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Pulsante Trasmetti. Connessione in corso"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Pulsante Trasmetti. Connesso"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Trasmetti a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Ricerca di dispositivi in corso"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Scollega"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Espandi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Comprimi"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Copertina"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Dispositivo di scorrimento del volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nessun contenuto multimediale selezionato"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nessuna informazione disponibile"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Trasmissione dello schermo in corso"</string>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
index 8b52adf..be705a6 100644
--- a/v7/mediarouter/res/values-iw/strings.xml
+++ b/v7/mediarouter/res/values-iw/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"מערכת"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"מכשירים"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"‏לחצן הפעלת Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"‏לחצן הפעלת Cast. מנותק"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"‏לחצן הפעלת Cast. מתחבר"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"‏לחצן הפעלת Cast. מחובר"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"העבר אל"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"מחפש מכשירים"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"נתק"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"הרחב"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"כווץ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"עטיפת אלבום"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"מחוון עוצמה"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"לא נבחרה מדיה"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"אין מידע זמין"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"העברת מסך מתבצעת"</string>
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
index b126965..75d75d6 100644
--- a/v7/mediarouter/res/values-ja/strings.xml
+++ b/v7/mediarouter/res/values-ja/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"システム"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"端末"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"キャストアイコン"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"キャスト アイコン。接続解除済み"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"キャスト アイコン。接続中"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"キャスト アイコン。接続済み"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"キャストするデバイス"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"端末を検索しています"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"接続を解除"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折りたたむ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"アルバムアート"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量スライダー"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"メディアが選択されていません"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"情報がありません"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"画面をキャストしています"</string>
diff --git a/v7/mediarouter/res/values-ka-rGE/strings.xml b/v7/mediarouter/res/values-ka-rGE/strings.xml
index 046e361..3bcc513 100644
--- a/v7/mediarouter/res/values-ka-rGE/strings.xml
+++ b/v7/mediarouter/res/values-ka-rGE/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"სისტემა"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"მოწყობილობები"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ტრანსლირების ღილაკი"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ტრანსლირების ღილაკი. გათიშული"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ტრანსლირების ღილაკი. მიმდინარეობს დაკავშირება"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ტრანსლირების ღილაკი. დაკავშირებული"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ტრანსლირებული"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"მიმდინარეობს მოწყობილობების მოძიება"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"კავშირის გაწყვეტა"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"გაშლა"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ჩაკეცვა"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ალბომის გარეკანი"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ხმის სლაიდერი"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"მედია არჩეული არ არის"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ინფორმაცია არ არის ხელმისაწვდომი"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"მიმდინარეობს ეკრანის გადაცემა"</string>
diff --git a/v7/mediarouter/res/values-kk-rKZ/strings.xml b/v7/mediarouter/res/values-kk-rKZ/strings.xml
index 5cf4e5a..43e75b7 100644
--- a/v7/mediarouter/res/values-kk-rKZ/strings.xml
+++ b/v7/mediarouter/res/values-kk-rKZ/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Жүйе"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Құрылғылар"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Трансляциялау түймесі"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"\"Трансляциялау\" түймесі. Ажыратулы"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"\"Трансляциялау\" түймесі. Қосылуда"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"\"Трансляциялау\" түймесі. Қосылды"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Келесіге трансляциялау"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Құрылғыларды табу"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ажырату"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жаю"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жию"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Альбом шебері"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Дыбыс деңгейінің жүгірткісі"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ешбір тасушы таңдалмаған"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Қол жетімді ақпарат жоқ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Экранды трансляциялау"</string>
diff --git a/v7/mediarouter/res/values-km-rKH/strings.xml b/v7/mediarouter/res/values-km-rKH/strings.xml
index fd05668..44d88f4 100644
--- a/v7/mediarouter/res/values-km-rKH/strings.xml
+++ b/v7/mediarouter/res/values-km-rKH/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ប្រព័ន្ធ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ឧបករណ៍"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ប៊ូតុងខាស"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ខាសប៊ូតុង៖ បានកាត់ផ្តាច់"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ខាសប៊ូតុង៖ កំពុងភ្ជាប់"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ខាសប៊ូតុង៖ បានភ្ជាប់ហើយ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ខាសទៅ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ស្វែងរកឧបករណ៍"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ផ្ដាច់"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ពង្រីក"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"បង្រួម"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ស្នាដៃសិល្បៈអាល់ប៊ុម"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"របារកម្រិតសំឡេង"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"គ្មានការជ្រើសមេឌៀទេ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"មិនមានព័ត៌មានទេ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"កំពុងខាសអេក្រង់"</string>
diff --git a/v7/mediarouter/res/values-kn-rIN/strings.xml b/v7/mediarouter/res/values-kn-rIN/strings.xml
index 9cae5be..193d449 100644
--- a/v7/mediarouter/res/values-kn-rIN/strings.xml
+++ b/v7/mediarouter/res/values-kn-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ಸಿಸ್ಟಂ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ಸಾಧನಗಳು"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ಬಿತ್ತರಿಸು ಬಟನ್‌"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ಇದಕ್ಕೆ ಬಿತ್ತರಿಸಿ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ವಿಸ್ತರಿಸು"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ಸಂಕುಚಿಸು"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ಆಲ್ಬಮ್ ಕಲೆ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ವಾಲ್ಯೂಮ್ ಸ್ಲೈಡರ್"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ಯಾವುದೇ ಮಾಧ್ಯಮ ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ಪರದೆಯನ್ನು ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
index 7f53382..242560a 100644
--- a/v7/mediarouter/res/values-ko/strings.xml
+++ b/v7/mediarouter/res/values-ko/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"시스템"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"기기"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"전송 버튼"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"전송 버튼. 연결 해제됨"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"전송 버튼. 연결 중"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"전송 버튼. 연결됨"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"전송할 기기"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"기기를 찾는 중"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"연결 해제"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"펼치기"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"접기"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"앨범아트"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"볼륨 슬라이더"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"선택한 미디어 없음"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"정보가 없습니다."</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"화면 전송 중"</string>
diff --git a/v7/mediarouter/res/values-ky-rKG/strings.xml b/v7/mediarouter/res/values-ky-rKG/strings.xml
index 99201dc..0898ade 100644
--- a/v7/mediarouter/res/values-ky-rKG/strings.xml
+++ b/v7/mediarouter/res/values-ky-rKG/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Тутум"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Түзмөктөр"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Тышкы экранга чыгаруу баскычы"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Тышкы экранга чыгаруу баскычы. Түзмөк ажырап турат."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Тышкы экранга чыгаруу баскычы. Түзмөк туташууда"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Тышкы экранга чыгаруу баскычы. Түзмөк туташып турат"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Төмөнкүгө чыгаруу"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Түзмөктөр изделүүдө"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ажыратуу"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жайып көрсөтүү"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жыйыштыруу"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Альбом мукабасы"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Үндү катуулатуучу сыдырма"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Бир да медиа файл тандалган жок"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Эч маалымат жок"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Тышкы экранга чыгарылууда"</string>
diff --git a/v7/mediarouter/res/values-lo-rLA/strings.xml b/v7/mediarouter/res/values-lo-rLA/strings.xml
index 2765364..65b3472 100644
--- a/v7/mediarouter/res/values-lo-rLA/strings.xml
+++ b/v7/mediarouter/res/values-lo-rLA/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ລະບົບ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ອຸປະກອນ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ປຸ່ມ​ຄາ​ສ​ທ໌"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ປຸ່ມສົ່ງສັນຍານ. ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ປຸ່ມສົ່ງສັນຍານ. ກຳລັງເຊື່ອມຕໍ່"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ປຸ່ມສົ່ງສັນຍານ. ເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ຄາ​ສ​ທ໌​ຫາ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ກຳລັງ​ຊອກ​ຫາ​ອຸ​ປະ​ກອນ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ຕັດການເຊື່ອມຕໍ່"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ຂະຫຍາຍ"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ຫຍໍ້ລົງ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ໜ້າປົກອະລະບໍ້າ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ຕົວປັບລະດັບສຽງ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ບໍ່​ໄດ້​ເລືອກ​ມີ​ເດຍ​ໃດ​ໄວ້"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ບໍ່​ມີ​ຂໍ້​ມູນ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ການສົ່ງພາບໜ້າຈໍ"</string>
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
index 208752f..35931cf 100644
--- a/v7/mediarouter/res/values-lt/strings.xml
+++ b/v7/mediarouter/res/values-lt/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Įrenginiai"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Perdavimo mygtukas"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Perdavimo mygtukas. Atsijungta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Perdavimo mygtukas. Prisijungiama"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Perdavimo mygtukas. Prisijungta"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Perduoti į"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Randami įrenginiai"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Atjungti"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Išskleisti"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sutraukti"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumo viršelis"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Garsumo šliaužiklis"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nepasirinkta jokia medija"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacija nepasiekiama"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Perduodamas ekranas"</string>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
index 832a3ba..c146174 100644
--- a/v7/mediarouter/res/values-lv/strings.xml
+++ b/v7/mediarouter/res/values-lv/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistēma"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Ierīces"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Apraides poga"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Apraides poga. Savienojums pārtraukts"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Apraides poga. Notiek savienojuma izveide"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Apraides poga. Savienojums izveidots"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Apraidīšana uz ierīci"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Notiek ierīču meklēšana"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Atvienot"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Izvērst"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sakļaut"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albuma vāciņš"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Skaļuma slīdnis"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nav atlasīti multivides faili"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nav pieejama informācija"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Notiek ekrāna apraide"</string>
diff --git a/v7/mediarouter/res/values-mk-rMK/strings.xml b/v7/mediarouter/res/values-mk-rMK/strings.xml
index 726e285..6fd428f 100644
--- a/v7/mediarouter/res/values-mk-rMK/strings.xml
+++ b/v7/mediarouter/res/values-mk-rMK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Уреди"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Копчето за Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Копче за Cast. Исклучено"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Копче за Cast. Се поврзува"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Копче за Cast. Поврзано"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Емитувај на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Наоѓање уреди"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Исклучи"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Собери"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Корица на албум"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Лизгач за јачина на звук"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Не се избрани медиуми"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Нема достапни информации"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Екранот се емитува"</string>
diff --git a/v7/mediarouter/res/values-ml-rIN/strings.xml b/v7/mediarouter/res/values-ml-rIN/strings.xml
index b1d2cbe..63a37f8 100644
--- a/v7/mediarouter/res/values-ml-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ml-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ടാപ്പുചെയ്യുക"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"കാസ്റ്റ് ബട്ടൺ. വിച്ഛേദിച്ചു"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"കാസ്റ്റ് ബട്ടൺ. കണക്‌റ്റുചെയ്യുന്നു"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റുചെയ്തു"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ഇതിലേക്ക് കാസ്റ്റുചെയ്യുക"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ഉപകരണങ്ങൾ കണ്ടെത്തുന്നു"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"വിച്ഛേദിക്കുക"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"വികസിപ്പിക്കുക"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ചുരുക്കുക"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ആൽബം ആർട്ട്"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"വോളിയം സ്ലൈഡർ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"മീഡിയയൊന്നും തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"സ്‌ക്രീൻ കാസ്റ്റുചെയ്യുന്നു"</string>
diff --git a/v7/mediarouter/res/values-mn-rMN/strings.xml b/v7/mediarouter/res/values-mn-rMN/strings.xml
index d07d314..1197bfe 100644
--- a/v7/mediarouter/res/values-mn-rMN/strings.xml
+++ b/v7/mediarouter/res/values-mn-rMN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Төхөөрөмжүүд"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Дамжуулах товчлуур"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Дамжуулах товчлуур. Салсан"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Дамжуулах товчлуур. Холбож байна"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Дамжуулах товчлуур. Холбогдсон"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Дамжуулах"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Төхөөрөмж хайж байна"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Салгах"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Дэлгэх"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Хураах"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Цомгийн зураг"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Дууны түвшин тааруулагч"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ямар ч медиа сонгоогүй"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Мэдээлэл байхгүй байна"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Дэлгэцийг дамжуулж байна"</string>
diff --git a/v7/mediarouter/res/values-mr-rIN/strings.xml b/v7/mediarouter/res/values-mr-rIN/strings.xml
index 4e24aff..40d7d66 100644
--- a/v7/mediarouter/res/values-mr-rIN/strings.xml
+++ b/v7/mediarouter/res/values-mr-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट बटण"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट बटण. डिस्कनेक्ट केले"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट बटण. कनेक्ट करीत आहे"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट बटण. कनेक्ट केले"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"यावर कास्ट करा"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"डिव्हाइसेस शोधत आहे"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्‍कनेक्‍ट करा"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करा"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संकुचित करा"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"अल्बम कला"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"व्हॉल्यूम स्लायडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"मीडिया निवडला नाही"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोणतीही माहिती उपलब्ध नाही"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्‍ट करीत आहे"</string>
diff --git a/v7/mediarouter/res/values-ms-rMY/strings.xml b/v7/mediarouter/res/values-ms-rMY/strings.xml
index 2a4cd1c..cc32b96 100644
--- a/v7/mediarouter/res/values-ms-rMY/strings.xml
+++ b/v7/mediarouter/res/values-ms-rMY/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Peranti"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Butang Hantar"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butang hantar. Sambungan diputuskan"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butang hantar. Menyambung"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butang hantar. Disambungkan"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Hantar ke"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari peranti"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kembangkan"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Runtuhkan"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Seni album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Peluncur kelantangan"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tiada media dipilih"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Maklumat tidak tersedia"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Menghantar skrin"</string>
diff --git a/v7/mediarouter/res/values-my-rMM/strings.xml b/v7/mediarouter/res/values-my-rMM/strings.xml
index eca8835..e31cc92 100644
--- a/v7/mediarouter/res/values-my-rMM/strings.xml
+++ b/v7/mediarouter/res/values-my-rMM/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"စနစ်"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"စက်ပစ္စည်းများ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ကာစ်တ်လုပ်ရန် ခလုတ်"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ကာစ်ခလုတ်။ ချိတ်ဆက်မထားပါ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ကာစ်ခလုတ်။ ချိတ်ဆက်နေသည်"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ကာစ်ခလုတ်။ ချိတ်ဆက်ထားသည်"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"သို့ ကာစ်တ်လုပ်ရန်"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"စက်ပစ္စည်းများ ရှာဖွေခြင်း"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ဆက်သွယ်မှု ဖြတ်ရန်"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ဖြန့်ချရန်၃"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ခေါက်သိမ်းရန်..."</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"အယ်လ်ဘမ်ပုံ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"အသံအတိုးအကျယ်ချိန်သည့် ဆလိုက်ဒါ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"မည်သည့်မီဒီမှ မရွေးချယ်ထားပါ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"အချက်အလက် မရရှိနိုင်ပါ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"တည်းဖြတ်ရေး မျက်နှာပြင်"</string>
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
index 27f9f03..97ca73c 100644
--- a/v7/mediarouter/res/values-nb/strings.xml
+++ b/v7/mediarouter/res/values-nb/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-ikonet"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frakoblet"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Kobler til"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Tilkoblet"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finner enheter"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Koble fra"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utvid"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafikk"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glidebryter for volum"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Du har ikke valgt noen medier"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ingen informasjon er tilgjengelig"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Caster skjermen"</string>
diff --git a/v7/mediarouter/res/values-ne-rNP/strings.xml b/v7/mediarouter/res/values-ne-rNP/strings.xml
index 6abadbf..0e48b45 100644
--- a/v7/mediarouter/res/values-ne-rNP/strings.xml
+++ b/v7/mediarouter/res/values-ne-rNP/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"प्रणाली"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"उपकरणहरू"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast बटन"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast बटन। जडान विच्छेद भयो"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast बटन। जडान हुँदै"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast बटन। जडान भयो"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"यसमा Cast गर्नुहोस्"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"यन्त्रहरू पत्ता लगाउँदै"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"विच्छेद गर्नुहोस्"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तार गर्नुहोस्"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त पार्नुहोस्"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"भोल्युमको स्लाइडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कुनै मिडिया चयन भएको छैन"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"जानकारी उपलब्ध छैन"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रिन cast गर्दै"</string>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
index 4a9346d..5c899fd 100644
--- a/v7/mediarouter/res/values-nl/strings.xml
+++ b/v7/mediarouter/res/values-nl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Systeem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Apparaten"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-icoon"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-icoon. Verbinding verbroken"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-icoon. Verbinding maken"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-icoon. Verbonden"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Casten naar"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Apparaten zoeken"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Loskoppelen"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Uitvouwen"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Samenvouwen"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumhoes"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeschuifregelaar"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media geselecteerd"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen informatie beschikbaar"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Scherm casten"</string>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa-rIN/strings.xml
index 842a8b4..258529d 100644
--- a/v7/mediarouter/res/values-pa-rIN/strings.xml
+++ b/v7/mediarouter/res/values-pa-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ਸਿਸਟਮ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ਡਿਵਾਈਸਾਂ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ਕਾਸਟ ਬਟਨ"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ਕਾਸਟ ਬਟਨ। ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ਕਾਸਟ ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ਕਾਸਟ ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ਇਸ ਨਾਲ ਕਾਸਟ ਕਰੋ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ਡਿਵਾਈਸਾਂ ਲੱਭ ਰਿਹਾ ਹੈ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ਬੰਦ ਕਰੋ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ਐਲਬਮ ਆਰਟ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ਵੌਲਯੂਮ ਸਲਾਈਡਰ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ਕੋਈ ਵੀ ਮੀਡੀਆ ਨਹੀਂ ਚੁਣਿਆ ਗਿਆ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ਕੋਈ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ਸਕ੍ਰੀਨ ਜੋੜ ਰਿਹਾ ਹੈ"</string>
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
index d66be1a..0320550 100644
--- a/v7/mediarouter/res/values-pl/strings.xml
+++ b/v7/mediarouter/res/values-pl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Urządzenia"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Przycisk Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Przycisk Prześlij ekran. Rozłączono"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Przycisk Prześlij ekran. Łączę"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Przycisk Prześlij ekran. Połączono"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Przesyłaj na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Znajdowanie urządzeń"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odłącz"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozwiń"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zwiń"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Okładka albumu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Suwak głośności"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie wybrano multimediów"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Brak informacji"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Przesyłam ekran"</string>
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/res/values-pt-rBR/strings.xml
index 4d7e6cc..2fd84b1 100644
--- a/v7/mediarouter/res/values-pt-rBR/strings.xml
+++ b/v7/mediarouter/res/values-pt-rBR/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
index 0c68b92..b62f363 100644
--- a/v7/mediarouter/res/values-pt-rPT/strings.xml
+++ b/v7/mediarouter/res/values-pt-rPT/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão Transmitir. Desligado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão Transmitir. A ligar..."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão Transmitir. Ligado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"A localizar dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desassociar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Reduzir"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Imagem do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controlo de deslize do volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhum suporte multimédia selecionado"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"A transmitir o ecrã"</string>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
index 4d7e6cc..2fd84b1 100644
--- a/v7/mediarouter/res/values-pt/strings.xml
+++ b/v7/mediarouter/res/values-pt/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
index 9fe26a9..769a0ac 100644
--- a/v7/mediarouter/res/values-ro/strings.xml
+++ b/v7/mediarouter/res/values-ro/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispozitive"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Butonul de proiecție"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butonul de proiecție. Deconectat"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butonul de proiecție. Se conectează"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butonul de proiecție. Conectat"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Proiectați pe"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Se caută dispozitive"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Deconectați-vă"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Extindeți"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Restrângeți"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Grafica albumului"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glisor pentru volum"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Niciun fișier media selectat"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nu sunt disponibile informații"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Se proiectează ecranul"</string>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
index 4607a8c..9bd2170 100644
--- a/v7/mediarouter/res/values-ru/strings.xml
+++ b/v7/mediarouter/res/values-ru/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляции"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляции. Устройство отключено."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляции. Устройство подключается."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляции. Устройство подключено."</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Выберите устройство"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Поиск устройств…"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Отключить"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Развернуть"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свернуть"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Обложка"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Регулятор громкости"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медиафайл не выбран"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Данных нет"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Подключение к удаленному монитору"</string>
diff --git a/v7/mediarouter/res/values-si-rLK/strings.xml b/v7/mediarouter/res/values-si-rLK/strings.xml
index 144a0d5..baeac3e 100644
--- a/v7/mediarouter/res/values-si-rLK/strings.xml
+++ b/v7/mediarouter/res/values-si-rLK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"පද්ධතිය"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"උපාංග"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"විකාශ බොත්තම"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"විකාශ බොත්තම. විසන්ධි කරන ලදී"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"විකාශ බොත්තම සම්බන්ධ කරමින්"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"විකාශ බොත්තම සම්බන්ධ කරන ලදී"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"විකාශය"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"උපාංග සෙවීම"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"විසන්ධි කරන්න"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"දිග හරින්න"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"හකුළන්න"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ඇල්බම කලාව"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"හඬ පරිමා ස්ලයිඩරය"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"මාධ්‍යය තෝරා නැත"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ලබා ගත හැකි තොරතුරු නොමැත"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"විකාශ තිරය"</string>
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
index b546bde..4a0f4bf 100644
--- a/v7/mediarouter/res/values-sk/strings.xml
+++ b/v7/mediarouter/res/values-sk/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Zariadenia"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačidlo prenosu"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačidlo prenosu. Odpojené"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačidlo prenosu. Pripája sa"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačidlo prenosu. Pripojené"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Prenos do"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Vyhľadávanie zariadení"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojiť"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbaliť"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zbaliť"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Obrázok albumu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posúvač hlasitosti"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie sú vybrané žiadne médiá"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nie sú k dispozícii žiadne informácie"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prenáša sa obrazovka"</string>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
index 110c548..4ca2bdc 100644
--- a/v7/mediarouter/res/values-sl/strings.xml
+++ b/v7/mediarouter/res/values-sl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Naprave"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za predvajanje"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za predvajanje. Povezava je prekinjena."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za predvajanje. Vzpostavljanje povezave."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za predvajanje. Povezava je vzpostavljena."</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Predvajanje prek:"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Iskanje naprav"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini povezavo"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Razširi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Strni"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Drsnik za glasnost"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ni izbrane predstavnosti"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Podatki niso na voljo"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Predvajanje zaslona"</string>
diff --git a/v7/mediarouter/res/values-sq-rAL/strings.xml b/v7/mediarouter/res/values-sq-rAL/strings.xml
index 8ed93c3..45e3a34 100644
--- a/v7/mediarouter/res/values-sq-rAL/strings.xml
+++ b/v7/mediarouter/res/values-sq-rAL/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistemi"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Pajisjet"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Butoni i transmetimit"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butoni i transmetimit. Je i shkëputur"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butoni i transmetimit. Po lidhet"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butoni i transmetimit. Je i lidhur"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmeto te"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Gjetja e pajisjeve"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Shkëpute"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zgjeroje"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Palose"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Kopertina e albumit"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Rrëshqitësi i volumit"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nuk u zgjodh asnjë media"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nuk jepet asnjë informacion"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Po transmeton ekranin"</string>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index 5a72bd4..bddc045 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Уређаји"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Дугме Пребаци"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Дугме Пребаци. Веза је прекинута"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Дугме Пребаци. Повезује се"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Дугме Пребаци. Повезан је"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Пребацујте на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Проналажење уређаја"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Прекини везу"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Скупи"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Омот албума"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Клизач за јачину звука"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Нема изабраних медија"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Нису доступне никакве информације"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Пребацује се екран"</string>
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
index 3724902..9597bf9 100644
--- a/v7/mediarouter/res/values-sv/strings.xml
+++ b/v7/mediarouter/res/values-sv/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knappen"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frånkopplad"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Ansluter"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Ansluten"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Casta till"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Letar efter enheter"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Koppla från"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utöka"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Komprimera"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Skivomslag"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volymreglage"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Inga media har valts"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Det finns ingen information"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skärmen castas"</string>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
index f12fd5c..f7ae8f5 100644
--- a/v7/mediarouter/res/values-sw/strings.xml
+++ b/v7/mediarouter/res/values-sw/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Mfumo"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Vifaa"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Kitufe cha kutuma"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Kitufe cha kutuma. Kimeondolewa"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Kitufe cha kutuma. Kinaunganisha"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Kitufe cha kutuma. Kimeunganishwa"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Tuma kwenye"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Inatafuta vifaa"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ondoa"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Panua"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Kunja"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Sanaa ya albamu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Kitelezi cha sauti"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Hakuna maudhui yaliyochaguliwa"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hakuna maelezo yaliyopatikana"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Inatuma skrini"</string>
diff --git a/v7/mediarouter/res/values-ta-rIN/strings.xml b/v7/mediarouter/res/values-ta-rIN/strings.xml
index c314178..0ef3fc3 100644
--- a/v7/mediarouter/res/values-ta-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ta-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"அமைப்பு"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"திரையிடு பட்டன்"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"அனுப்புதல் பொத்தான். துண்டிக்கப்பட்டது"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"அனுப்புதல் பொத்தான். இணைக்கிறது"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"அனுப்புதல் பொத்தான். இணைக்கப்பட்டது"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"இதில் திரையிடு"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"சாதனங்களைத் தேடுகிறது"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"தொடர்பைத் துண்டி"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"விரிவாக்கு"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"சுருக்கு"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ஆல்பம் ஆர்ட்"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ஒலியளவு ஸ்லைடர்"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"மீடியா எதுவும் தேர்ந்தெடுக்கப்படவில்லை"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"தகவல் எதுவுமில்லை"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"திரையை அனுப்புகிறீர்கள்"</string>
diff --git a/v7/mediarouter/res/values-te-rIN/strings.xml b/v7/mediarouter/res/values-te-rIN/strings.xml
index 59a4f19..c7ae34f 100644
--- a/v7/mediarouter/res/values-te-rIN/strings.xml
+++ b/v7/mediarouter/res/values-te-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"సిస్టమ్"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"పరికరాలు"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ప్రసారం చేయి బటన్"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ప్రసార బటన్. డిస్‌కనెక్ట్ చేయబడింది"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ప్రసార బటన్. కనెక్ట్ చేస్తోంది"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ప్రసార బటన్. కనెక్ట్ చేయబడింది"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"దీనికి ప్రసారం చేయండి"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"పరికరాలను కనుగొంటోంది"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"డిస్‌కనెక్ట్ చేయి"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"విస్తరింపజేస్తుంది"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"కుదిస్తుంది"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ఆల్బమ్ ఆర్ట్"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"వాల్యూమ్ స్లయిడర్"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"మీడియా ఏదీ ఎంచుకోబడలేదు"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"సమాచారం అందుబాటులో లేదు"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"స్క్రీన్‌ను ప్రసారం చేస్తోంది"</string>
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
index 1bfd091..219374c 100644
--- a/v7/mediarouter/res/values-th/strings.xml
+++ b/v7/mediarouter/res/values-th/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ระบบ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"อุปกรณ์"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ปุ่ม \"แคสต์\""</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ปุ่ม \"แคสต์\" ยกเลิกการเชื่อมต่อ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ปุ่ม \"แคสต์\" กำลังเชื่อมต่อ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ปุ่ม \"แคสต์\" เชื่อมต่อแล้ว"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"แคสต์ไปยัง"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"กำลังค้นหาอุปกรณ์"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ยกเลิกการเชื่อมต่อ"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ขยาย"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ยุบ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ปกอัลบั้ม"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"แถบเลื่อนปรับระดับเสียง"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ไม่ได้เลือกสื่อไว้"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ไม่มีข้อมูล"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"กำลังแคสต์หน้าจอ"</string>
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
index 82396e1..e2bb7c7 100644
--- a/v7/mediarouter/res/values-tl/strings.xml
+++ b/v7/mediarouter/res/values-tl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Mga Device"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Button na I-cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Button na I-cast. Nadiskonekta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Button na I-cast. Kumokonekta"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Button na I-cast. Nakakonekta"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"I-cast sa"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Naghahanap ng mga device"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Idiskonekta"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Palawakin"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"I-collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Slider ng volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Walang piniling media"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Walang available na impormasyon"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Kina-cast ang screen"</string>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
index e639963..187682f 100644
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ b/v7/mediarouter/res/values-tr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Yayın düğmesi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayınla düğmesi. Bağlantı kesildi"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayınla düğmesi. Bağlanıyor"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayınla düğmesi. Bağlandı"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Şuraya yayınla:"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar bulunuyor"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantıyı kes"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişlet"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Daralt"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albüm kapağı"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ses düzeyi kaydırma çubuğu"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Medya seçilmedi"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Bilgi yok"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayınlanıyor"</string>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/res/values-uk/strings.xml
index a768e2c..8c2a16a 100644
--- a/v7/mediarouter/res/values-uk/strings.xml
+++ b/v7/mediarouter/res/values-uk/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Пристрої"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляції"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляції. Від’єднано"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляції. Під’єднання"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляції. Під’єднано"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Транслювати на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Пошук пристроїв"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Відключити"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Розгорнути"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згорнути"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Обкладинка альбому"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Повзунок гучності"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медіа-файл не вибрано"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Немає даних"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Трансляція екрана"</string>
diff --git a/v7/mediarouter/res/values-ur-rPK/strings.xml b/v7/mediarouter/res/values-ur-rPK/strings.xml
index 5cb3b36..053373f 100644
--- a/v7/mediarouter/res/values-ur-rPK/strings.xml
+++ b/v7/mediarouter/res/values-ur-rPK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"سسٹم"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"آلات"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"کاسٹ کرنے کا بٹن"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"کاسٹ کرنے کا بٹن۔ غیر منسلک ہے"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"کاسٹ کرنے کا بٹن۔ منسلک ہو رہا ہے"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"کاسٹ کرنے کا بٹن۔ منسلک ہے"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"اس میں کاسٹ کریں"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"آلات تلاش ہو رہے ہیں"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"غیر منسلک کریں"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"پھیلائیں"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"سکیڑیں"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"البم آرٹ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"والیوم سلائیڈر"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"کوئی میڈیا منتخب نہیں ہے"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"کوئی معلومات دستیاب نہیں"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"سکرین کاسٹ ہو رہی ہے"</string>
diff --git a/v7/mediarouter/res/values-uz-rUZ/strings.xml b/v7/mediarouter/res/values-uz-rUZ/strings.xml
index 9955cdfd..9d1e455 100644
--- a/v7/mediarouter/res/values-uz-rUZ/strings.xml
+++ b/v7/mediarouter/res/values-uz-rUZ/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Tizim"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Qurilmalar"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Translatsiya tugmasi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Translatsiya tugmasi. Uzildi"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Translatsiya tugmasi. Ulanmoqda"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Translatsiya tugmasi. Ulandi"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Quyidagiga translatsiya qilish:"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Qurilmalarni topish"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ulanishni uzish"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Yoyish"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yig‘ish"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albom muqovasi"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ovoz balandligi slayderi"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Multimedia tanlamagan"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hech qanday ma’lumot yo‘q"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekranni translatsiya qilish"</string>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
index 0080e3e..488b9f0 100644
--- a/v7/mediarouter/res/values-vi/strings.xml
+++ b/v7/mediarouter/res/values-vi/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Hệ thống"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Thiết bị"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Nút truyền"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Nút truyền. Đã ngắt kết nối"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Nút truyền. Đang kết nối"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Nút truyền. Đã kết nối"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Truyền tới"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Tìm thiết bị"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ngắt kết nối"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mở rộng"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Thu gọn"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Ảnh bìa album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Thanh trượt âm lượng"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Không có phương tiện nào được chọn"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Không có thông tin nào"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Đang truyền màn hình"</string>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index aabe727..c22a91c 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"系统"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"设备"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"投射按钮"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投射按钮。已断开连接"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投射按钮。正在连接"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"投射按钮。已连接"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"投射到"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"正在查找设备"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"断开连接"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展开"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折叠"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"专辑封面"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑块"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"未选择任何媒体"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"没有任何相关信息"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投射屏幕"</string>
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
index d01c823..d17469b 100644
--- a/v7/mediarouter/res/values-zh-rHK/strings.xml
+++ b/v7/mediarouter/res/values-zh-rHK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投放按鈕。已解除連接"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投放按鈕。正在連接"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"投放按鈕。已連接"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"投放至"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"正在尋找裝置"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"中斷連線"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"專輯封面"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑桿"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"尚未選擇媒體"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"沒有詳細資料"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投放螢幕"</string>
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
index 68347e5..1a71c84 100644
--- a/v7/mediarouter/res/values-zh-rTW/strings.xml
+++ b/v7/mediarouter/res/values-zh-rTW/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投放按鈕;已中斷連線"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投放按鈕;連線中"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"投放按鈕;已連線"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"投放到"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"正在尋找裝置"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"中斷連線"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"專輯封面"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑桿"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"未選取任何媒體"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"沒有可用的資訊"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投放螢幕"</string>
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
index e50acc8..860aa09 100644
--- a/v7/mediarouter/res/values-zu/strings.xml
+++ b/v7/mediarouter/res/values-zu/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Isistimu"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Amadivayisi"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Inkinobho ye-Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Inkinobho yokusakaza. Kunqanyuliwe"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Inkinobho yokusakaza. Kuyaxhunywa"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Inkinobho yokusakaza. Kuxhunyiwe"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Sakaza ku-"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Ithola amadivayisi"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Nqamula"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Nweba"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Goqa"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Ubuciko be-albhamu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Isilayida sevolumu"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ayikho imidiya ekhethiwe"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Alukho ulwazi olutholakalayo"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Isikrini sokusakaza"</string>
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 1516261..9c7747c 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
@@ -46,9 +46,9 @@
     private static final String LOG_TAG = "ColorCutQuantizer";
     private static final boolean LOG_TIMINGS = false;
 
-    private static final int COMPONENT_RED = -3;
-    private static final int COMPONENT_GREEN = -2;
-    private static final int COMPONENT_BLUE = -1;
+    static final int COMPONENT_RED = -3;
+    static final int COMPONENT_GREEN = -2;
+    static final int COMPONENT_BLUE = -1;
 
     private static final int QUANTIZE_WORD_WIDTH = 5;
     private static final int QUANTIZE_WORD_MASK = (1 << QUANTIZE_WORD_WIDTH) - 1;
@@ -398,7 +398,7 @@
      *
      * @see Vbox#findSplitPoint()
      */
-    private static void modifySignificantOctet(final int[] a, final int dimension,
+    static void modifySignificantOctet(final int[] a, final int dimension,
             final int lower, final int upper) {
         switch (dimension) {
             case COMPONENT_RED:
@@ -469,7 +469,7 @@
     /**
      * Quantized RGB888 values to have a word width of {@value #QUANTIZE_WORD_WIDTH}.
      */
-    private static int approximateToRgb888(int r, int g, int b) {
+    static int approximateToRgb888(int r, int g, int b) {
         return Color.rgb(modifyWordWidth(r, QUANTIZE_WORD_WIDTH, 8),
                 modifyWordWidth(g, QUANTIZE_WORD_WIDTH, 8),
                 modifyWordWidth(b, QUANTIZE_WORD_WIDTH, 8));
@@ -482,21 +482,21 @@
     /**
      * @return red component of the quantized color
      */
-    private static int quantizedRed(int color) {
+    static int quantizedRed(int color) {
         return (color >> (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) & QUANTIZE_WORD_MASK;
     }
 
     /**
      * @return green component of a quantized color
      */
-    private static int quantizedGreen(int color) {
+    static int quantizedGreen(int color) {
         return (color >> QUANTIZE_WORD_WIDTH) & QUANTIZE_WORD_MASK;
     }
 
     /**
      * @return blue component of a quantized color
      */
-    private static int quantizedBlue(int color) {
+    static int quantizedBlue(int color) {
         return color & QUANTIZE_WORD_MASK;
     }
 
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
index 6d0368d..93570de 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
@@ -84,14 +84,14 @@
         void onGenerated(Palette palette);
     }
 
-    private static final int DEFAULT_RESIZE_BITMAP_AREA = 160 * 160;
-    private static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
+    static final int DEFAULT_RESIZE_BITMAP_AREA = 160 * 160;
+    static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
 
-    private static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
-    private static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
+    static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
+    static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
 
-    private static final String LOG_TAG = "Palette";
-    private static final boolean LOG_TIMINGS = false;
+    static final String LOG_TAG = "Palette";
+    static final boolean LOG_TIMINGS = false;
 
     /**
      * Start generating a {@link Palette} with the returned {@link Builder} instance.
@@ -151,7 +151,7 @@
 
     private final Swatch mDominantSwatch;
 
-    private Palette(List<Swatch> swatches, List<Target> targets) {
+    Palette(List<Swatch> swatches, List<Target> targets) {
         mSwatches = swatches;
         mTargets = targets;
 
@@ -345,7 +345,7 @@
         return mDominantSwatch != null ? mDominantSwatch.getRgb() : defaultColor;
     }
 
-    private void generate() {
+    void generate() {
         // We need to make sure that the scored targets are generated first. This is so that
         // inherited targets have something to inherit from
         for (int i = 0, count = mTargets.size(); i < count; i++) {
@@ -951,7 +951,7 @@
     /**
      * The default filter.
      */
-    private static final Filter DEFAULT_FILTER = new Filter() {
+    static final Filter DEFAULT_FILTER = new Filter() {
         private static final float BLACK_MAX_LIGHTNESS = 0.05f;
         private static final float WHITE_MIN_LIGHTNESS = 0.95f;
 
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Target.java b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
index d1e0742..640970b 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Target.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
@@ -47,13 +47,13 @@
     private static final float WEIGHT_LUMA = 0.52f;
     private static final float WEIGHT_POPULATION = 0.24f;
 
-    private static final int INDEX_MIN = 0;
-    private static final int INDEX_TARGET = 1;
-    private static final int INDEX_MAX = 2;
+    static final int INDEX_MIN = 0;
+    static final int INDEX_TARGET = 1;
+    static final int INDEX_MAX = 2;
 
-    private static final int INDEX_WEIGHT_SAT = 0;
-    private static final int INDEX_WEIGHT_LUMA = 1;
-    private static final int INDEX_WEIGHT_POP = 2;
+    static final int INDEX_WEIGHT_SAT = 0;
+    static final int INDEX_WEIGHT_LUMA = 1;
+    static final int INDEX_WEIGHT_POP = 2;
 
     /**
      * A target which has the characteristics of a vibrant color which is light in luminance.
@@ -111,18 +111,18 @@
         setDefaultMutedSaturationValues(DARK_MUTED);
     }
 
-    private final float[] mSaturationTargets = new float[3];
-    private final float[] mLightnessTargets = new float[3];
-    private final float[] mWeights = new float[3];
-    private boolean mIsExclusive = true; // default to true
+    final float[] mSaturationTargets = new float[3];
+    final float[] mLightnessTargets = new float[3];
+    final float[] mWeights = new float[3];
+    boolean mIsExclusive = true; // default to true
 
-    private Target() {
+    Target() {
         setTargetDefaultValues(mSaturationTargets);
         setTargetDefaultValues(mLightnessTargets);
         setDefaultWeights();
     }
 
-    private Target(Target from) {
+    Target(Target from) {
         System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
                 mSaturationTargets.length);
         System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
index d419dd2..4762548 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
@@ -19,6 +19,7 @@
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
@@ -295,7 +296,7 @@
 
         final View view = inflater.inflate(pl.resId, parent, false);
         if (view.getBackground() == null) {
-            view.setBackgroundDrawable(background);
+            ViewCompat.setBackground(view, background);
         }
 
         final ViewGroup widgetFrame = (ViewGroup) view.findViewById(android.R.id.widget_frame);
diff --git a/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java b/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
new file mode 100644
index 0000000..6229b20
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * DividerItemDecoration is a {@link RecyclerView.ItemDecoration} that can be used as a divider
+ * between items of a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and
+ * {@link #VERTICAL} orientations.
+ *
+ * <pre>
+ *     mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
+ *             mLayoutManager.getOrientation());
+ *     recyclerView.addItemDecoration(mDividerItemDecoration);
+ * </pre>
+ */
+public class DividerItemDecoration extends RecyclerView.ItemDecoration {
+    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+    public static final int VERTICAL = LinearLayout.VERTICAL;
+
+    private static final int[] ATTRS = new int[]{ android.R.attr.listDivider };
+
+    private Drawable mDivider;
+
+    /**
+     * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}.
+     */
+    private int mOrientation;
+
+    private final Rect mBounds = new Rect();
+
+    /**
+     * Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a
+     * {@link LinearLayoutManager}.
+     *
+     * @param context Current context, it will be used to access resources.
+     * @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}.
+     */
+    public DividerItemDecoration(Context context, int orientation) {
+        final TypedArray a = context.obtainStyledAttributes(ATTRS);
+        mDivider = a.getDrawable(0);
+        a.recycle();
+        setOrientation(orientation);
+    }
+
+    /**
+     * Sets the orientation for this divider. This should be called if
+     * {@link RecyclerView.LayoutManager} changes orientation.
+     *
+     * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
+     */
+    public void setOrientation(int orientation) {
+        if (orientation != HORIZONTAL && orientation != VERTICAL) {
+            throw new IllegalArgumentException(
+                    "Invalid orientation. It should be either HORIZONTAL or VERTICAL");
+        }
+        mOrientation = orientation;
+    }
+
+    /**
+     * Sets the {@link Drawable} for this divider.
+     *
+     * @param drawable Drawable that should be used as a divider.
+     */
+    public void setDrawable(@NonNull Drawable drawable) {
+        if (drawable == null) {
+            throw new IllegalArgumentException("Drawable cannot be null.");
+        }
+        mDivider = drawable;
+    }
+
+    @Override
+    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+        if (parent.getLayoutManager() == null) {
+            return;
+        }
+        if (mOrientation == VERTICAL) {
+            drawVertical(c, parent);
+        } else {
+            drawHorizontal(c, parent);
+        }
+    }
+
+    private void drawVertical(Canvas canvas, RecyclerView parent) {
+        canvas.save();
+        final int left;
+        final int right;
+        if (parent.getClipToPadding()) {
+            left = parent.getPaddingLeft();
+            right = parent.getWidth() - parent.getPaddingRight();
+            canvas.clipRect(left, parent.getPaddingTop(), right,
+                    parent.getHeight() - parent.getPaddingBottom());
+        } else {
+            left = 0;
+            right = parent.getWidth();
+        }
+
+        final int childCount = parent.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = parent.getChildAt(i);
+            parent.getDecoratedBoundsWithMargins(child, mBounds);
+            final int bottom = mBounds.bottom + Math.round(ViewCompat.getTranslationY(child));
+            final int top = bottom - mDivider.getIntrinsicHeight();
+            mDivider.setBounds(left, top, right, bottom);
+            mDivider.draw(canvas);
+        }
+        canvas.restore();
+    }
+
+    private void drawHorizontal(Canvas canvas, RecyclerView parent) {
+        canvas.save();
+        final int top;
+        final int bottom;
+        if (parent.getClipToPadding()) {
+            top = parent.getPaddingTop();
+            bottom = parent.getHeight() - parent.getPaddingBottom();
+            canvas.clipRect(parent.getPaddingLeft(), top,
+                    parent.getWidth() - parent.getPaddingRight(), bottom);
+        } else {
+            top = 0;
+            bottom = parent.getHeight();
+        }
+
+        final int childCount = parent.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = parent.getChildAt(i);
+            parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
+            final int right = mBounds.right + Math.round(ViewCompat.getTranslationX(child));
+            final int left = right - mDivider.getIntrinsicWidth();
+            mDivider.setBounds(left, top, right, bottom);
+            mDivider.draw(canvas);
+        }
+        canvas.restore();
+    }
+
+    @Override
+    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+            RecyclerView.State state) {
+        if (mOrientation == VERTICAL) {
+            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
+        } else {
+            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
+        }
+    }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index 4d19163..4293852 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -505,6 +505,27 @@
     }
 
     @Override
+    int getItemPrefetchCount() {
+        return mSpanCount;
+    }
+
+    @Override
+    int gatherPrefetchIndicesForLayoutState(RecyclerView.State state, LayoutState layoutState,
+                int[] outIndices) {
+        int remainingSpan = mSpanCount;
+        int count = 0;
+        while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) {
+            final int pos = layoutState.mCurrentPosition;
+            outIndices[count] = pos;
+            final int spanSize = mSpanSizeLookup.getSpanSize(pos);
+            remainingSpan -= spanSize;
+            layoutState.mCurrentPosition += layoutState.mItemDirection;
+            count++;
+        }
+        return count;
+    }
+
+    @Override
     void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
             LayoutState layoutState, LayoutChunkResult result) {
         final int otherDirSpecMode = mOrientationHelper.getModeInOther();
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index 5ee2537..5fbb67c 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -1180,6 +1180,36 @@
                 && mOrientationHelper.getEnd() == 0;
     }
 
+    @Override
+    int getItemPrefetchCount() {
+        return 1;
+    }
+
+    int gatherPrefetchIndicesForLayoutState(RecyclerView.State state, LayoutState layoutState,
+            int[] outIndices) {
+        final int pos = layoutState.mCurrentPosition;
+        if (pos >= 0 && pos < state.getItemCount()) {
+            outIndices[0] = pos;
+            return 1;
+        }
+        return 0;
+    }
+
+    @Override
+    int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+        int delta = (mOrientation == HORIZONTAL) ? dx : dy;
+        if (getChildCount() == 0 || delta == 0) {
+            // can't support this scroll, so don't bother prefetching
+            return 0;
+        }
+
+
+        final int layoutDirection = delta > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
+        final int absDy = Math.abs(delta);
+        updateLayoutState(layoutDirection, absDy, true, state);
+        return gatherPrefetchIndicesForLayoutState(state, mLayoutState, outIndices);
+    }
+
     int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
         if (getChildCount() == 0 || dy == 0) {
             return 0;
@@ -1323,7 +1353,6 @@
                 }
             }
         }
-
     }
 
     /**
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 87ebb16..47e9933 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -58,6 +58,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TypedValue;
+import android.view.Display;
 import android.view.FocusFinder;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -74,8 +75,10 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import static android.support.v7.widget.AdapterHelper.Callback;
 import static android.support.v7.widget.AdapterHelper.UpdateOp;
@@ -174,6 +177,14 @@
      */
     static final boolean ALLOW_SIZE_IN_UNSPECIFIED_SPEC = Build.VERSION.SDK_INT >= 23;
 
+    static final boolean POST_UPDATES_ON_ANIMATION = Build.VERSION.SDK_INT >= 16;
+
+    /**
+     * On L+, with RenderThread, the UI thread has idle time after it has passed a frame off to
+     * RenderThread but before the next frame begins. We schedule prefetch work in this window.
+     */
+    private static final boolean ALLOW_PREFETCHING = Build.VERSION.SDK_INT >= 21;
+
     static final boolean DISPATCH_TEMP_DETACH = false;
     public static final int HORIZONTAL = 0;
     public static final int VERTICAL = 1;
@@ -237,6 +248,11 @@
     private static final String TRACE_BIND_VIEW_TAG = "RV OnBindView";
 
     /**
+     * RecyclerView is attempting to pre-populate off screen views.
+     */
+    private static final String TRACE_PREFETCH_TAG = "RV Prefetch";
+
+    /**
      * RecyclerView is creating a new View.
      * If too many of these present in Systrace:
      * - There might be a problem in Recycling (e.g. custom Animations that set transient state and
@@ -330,7 +346,7 @@
     // binary OR of change events that were eaten during a layout or scroll.
     private int mEatenAccessibilityChangeFlags;
     private boolean mAdapterUpdateDuringMeasure;
-    private final boolean mPostUpdatesOnAnimation;
+
     private final AccessibilityManager mAccessibilityManager;
     private List<OnChildAttachStateChangeListener> mOnChildAttachStateListeners;
 
@@ -403,6 +419,9 @@
 
     private final ViewFlinger mViewFlinger = new ViewFlinger();
 
+    private static final long MIN_PREFETCH_TIME_NANOS = TimeUnit.MILLISECONDS.toNanos(4);
+    ViewPrefetcher mViewPrefetcher = ALLOW_PREFETCHING ? new ViewPrefetcher() : null;
+
     final State mState = new State();
 
     private OnScrollListener mScrollListener;
@@ -501,8 +520,6 @@
         }
         setScrollContainer(true);
         setFocusableInTouchMode(true);
-        final int version = Build.VERSION.SDK_INT;
-        mPostUpdatesOnAnimation = version >= 16;
 
         final ViewConfiguration vc = ViewConfiguration.get(context);
         mTouchSlop = vc.getScaledTouchSlop();
@@ -854,6 +871,22 @@
     }
 
     /**
+     * Returns whether this RecyclerView will clip its children to its padding, and resize (but
+     * not clip) any EdgeEffect to the padded region, if padding is present.
+     * <p>
+     * By default, children are clipped to the padding of their parent
+     * RecyclerView. This clipping behavior is only enabled if padding is non-zero.
+     *
+     * @return true if this RecyclerView clips children to its padding and resizes (but doesn't
+     *         clip) any EdgeEffect to the padded region, false otherwise.
+     *
+     * @attr name android:clipToPadding
+     */
+    public boolean getClipToPadding() {
+        return mClipToPadding;
+    }
+
+    /**
      * Configure the scrolling touch slop for a specific use case.
      *
      * Set up the RecyclerView's scrolling motion threshold based on common usages.
@@ -1092,6 +1125,7 @@
                 mLayout.dispatchAttachedToWindow(this);
             }
         }
+        mRecycler.updateViewCacheSize();
         requestLayout();
     }
 
@@ -2341,6 +2375,13 @@
             mLayout.dispatchAttachedToWindow(this);
         }
         mPostedAnimatorRunner = false;
+        Display display = ViewCompat.getDisplay(this);
+        if (ALLOW_PREFETCHING
+                && display != null
+                && display.getRefreshRate() >= 30.0f) {
+            // break 60 fps assumption if data appears good
+            mViewPrefetcher.mFrameIntervalNanos = (long) (1000000000 / display.getRefreshRate());
+        }
     }
 
     @Override
@@ -2707,6 +2748,9 @@
                             vtev)) {
                         getParent().requestDisallowInterceptTouchEvent(true);
                     }
+                    if (ALLOW_PREFETCHING) {
+                        mViewPrefetcher.postFromTraversal(dx, dy);
+                    }
                 }
             } break;
 
@@ -4235,6 +4279,26 @@
         }
     }
 
+    /**
+     * Returns the bounds of the view including its decoration and margins.
+     *
+     * @param view The view element to check
+     * @param outBounds A rect that will receive the bounds of the element including its
+     *                  decoration and margins.
+     */
+    public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
+        getDecoratedBoundsWithMarginsInt(view, outBounds);
+    }
+
+    static void getDecoratedBoundsWithMarginsInt(View view, Rect outBounds) {
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        final Rect insets = lp.mDecorInsets;
+        outBounds.set(view.getLeft() - insets.left - lp.leftMargin,
+                view.getTop() - insets.top - lp.topMargin,
+                view.getRight() + insets.right + lp.rightMargin,
+                view.getBottom() + insets.bottom + lp.bottomMargin);
+    }
+
     Rect getItemDecorInsetsForChild(View child) {
         final LayoutParams lp = (LayoutParams) child.getLayoutParams();
         if (!lp.mInsetsDirty) {
@@ -4362,6 +4426,76 @@
                 || mAdapterHelper.hasPendingUpdates();
     }
 
+    /**
+     * Runs prefetch work immediately after a traversal, in the downtime while the UI thread is
+     * waiting for VSYNC.
+     */
+    class ViewPrefetcher implements Runnable {
+        long mFrameIntervalNanos = TimeUnit.MILLISECONDS.toNanos(16);
+
+        long mPostTimeNanos;
+        private int mDx;
+        private int mDy;
+
+        private int[] mItemPrefetchArray;
+
+        /**
+         * Schedule a prefetch immediately after the current traversal.
+         */
+        public void postFromTraversal(int dx, int dy) {
+            if (ALLOW_PREFETCHING
+                    && mAdapter != null
+                    && mLayout != null
+                    && mLayout.getItemPrefetchCount() > 0) {
+                mDx = dx;
+                mDy = dy;
+                mPostTimeNanos = System.nanoTime();
+                RecyclerView.this.post(this);
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                TraceCompat.beginSection(TRACE_PREFETCH_TAG);
+                final int prefetchCount = mLayout.getItemPrefetchCount();
+                if (mAdapter == null
+                        || mLayout == null
+                        || !mLayout.isItemPrefetchEnabled()
+                        || prefetchCount < 1
+                        || hasPendingAdapterUpdates()) {
+                    // abort - no work
+                    return;
+                }
+
+                // Query last vsync so we can predict next one. Note that drawing time not yet
+                // valid in animation/input callbacks, so query it here to be safe.
+                long lastFrameVsyncNanos = TimeUnit.MILLISECONDS.toNanos(getDrawingTime());
+                if (lastFrameVsyncNanos == 0) {
+                    // abort - couldn't get last vsync for estimating next
+                    return;
+                }
+
+                long nowNanos = System.nanoTime();
+                long nextFrameNanos = lastFrameVsyncNanos + mFrameIntervalNanos;
+                if (nowNanos - mPostTimeNanos > mFrameIntervalNanos
+                        || nextFrameNanos - nowNanos < MIN_PREFETCH_TIME_NANOS) {
+                    // abort - Executing either too far after post, or too near next scheduled vsync
+                    return;
+                }
+
+                if (mItemPrefetchArray == null || mItemPrefetchArray.length < prefetchCount) {
+                    mItemPrefetchArray = new int[prefetchCount];
+                }
+                Arrays.fill(mItemPrefetchArray, -1);
+                int viewCount = mLayout.gatherPrefetchIndices(mDx, mDy, mState, mItemPrefetchArray);
+                mRecycler.prefetch(mItemPrefetchArray, viewCount);
+            } finally {
+                TraceCompat.endSection();
+            }
+        }
+    }
+
     private class ViewFlinger implements Runnable {
         private int mLastFlingX;
         private int mLastFlingY;
@@ -4478,6 +4612,9 @@
                     setScrollState(SCROLL_STATE_IDLE); // setting state to idle will stop this.
                 } else {
                     postOnAnimation();
+                    if (ALLOW_PREFETCHING) {
+                        mViewPrefetcher.postFromTraversal(dx, dy);
+                    }
                 }
             }
             // call this after the onAnimation is complete not to have inconsistent callbacks etc.
@@ -4651,7 +4788,7 @@
         }
 
         void triggerUpdateProcessor() {
-            if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) {
+            if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
                 ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
             } else {
                 mAdapterUpdateDuringMeasure = true;
@@ -4794,13 +4931,14 @@
         private final List<ViewHolder>
                 mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
 
-        private int mViewCacheMax = DEFAULT_CACHE_SIZE;
+        private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
+        int mViewCacheMax = DEFAULT_CACHE_SIZE;
 
         private RecycledViewPool mRecyclerPool;
 
         private ViewCacheExtension mViewCacheExtension;
 
-        private static final int DEFAULT_CACHE_SIZE = 2;
+        static final int DEFAULT_CACHE_SIZE = 2;
 
         /**
          * Clear scrap views out of this recycler. Detached views contained within a
@@ -4817,9 +4955,19 @@
          * @param viewCount Number of views to keep before sending views to the shared pool
          */
         public void setViewCacheSize(int viewCount) {
-            mViewCacheMax = viewCount;
+            mRequestedCacheMax = viewCount;
+            updateViewCacheSize();
+        }
+
+        void updateViewCacheSize() {
+            int extraCache = 0;
+            if (mLayout != null && ALLOW_PREFETCHING) {
+                extraCache = mLayout.isItemPrefetchEnabled() ? mLayout.getItemPrefetchCount() : 0;
+            }
+            mViewCacheMax = mRequestedCacheMax + extraCache;
             // first, try the views that can be recycled
-            for (int i = mCachedViews.size() - 1; i >= 0 && mCachedViews.size() > viewCount; i--) {
+            for (int i = mCachedViews.size() - 1;
+                    i >= 0 && mCachedViews.size() > mViewCacheMax; i--) {
                 recycleCachedViewAt(i);
             }
         }
@@ -5698,6 +5846,21 @@
                 }
             }
         }
+
+        void prefetch(int[] itemPrefetchArray, int viewCount) {
+            if (viewCount == 0) return;
+
+            int childPosition = itemPrefetchArray[viewCount - 1];
+            if (childPosition < 0) {
+                throw new IllegalArgumentException("Recycler requested to prefetch invalid view "
+                        + childPosition);
+            }
+            View prefetchView = getViewForPosition(childPosition);
+            if (viewCount > 1) {
+                prefetch(itemPrefetchArray, viewCount - 1);
+            }
+            recycleView(prefetchView);
+        }
     }
 
     /**
@@ -6343,6 +6506,7 @@
          */
         private boolean mMeasurementCacheEnabled = true;
 
+        private boolean mItemPrefetchEnabled = true;
 
         /**
          * These measure specs might be the measure specs that were passed into RecyclerView's
@@ -6624,6 +6788,52 @@
             return false;
         }
 
+        /**
+         * Sets whether the LayoutManager should be queried for views outside of
+         * its viewport while the UI thread is idle between frames.
+         *
+         * <p>If enabled, the LayoutManager will be queried for items to inflate/bind in between
+         * view system traversals on devices running API 21 or greater. Default value is true.</p>
+         *
+         * <p>On platforms API level 21 and higher, the UI thread is idle between passing a frame
+         * to RenderThread and the starting up its next frame at the next VSync pulse. By
+         * prefetching out of window views in this time period, delays from inflation and view
+         * binding are much less likely to cause jank and stuttering during scrolls and flings.</p>
+         *
+         * <p>While prefetch is enabled, it will have the side effect of expanding the effective
+         * size of the View cache to hold prefetched views.</p>
+         *
+         * @param enabled <code>True</code> if items should be prefetched in between traversals.
+         *
+         * @see #isItemPrefetchEnabled()
+         */
+        public final void setItemPrefetchEnabled(boolean enabled) {
+            if (enabled != mItemPrefetchEnabled) {
+                mItemPrefetchEnabled = enabled;
+                if (mRecyclerView != null) {
+                    mRecyclerView.mRecycler.updateViewCacheSize();
+                }
+            }
+        }
+
+        /**
+         * Sets whether the LayoutManager should be queried for views outside of
+         * its viewport while the UI thread is idle between frames.
+         *
+         * @see #setItemPrefetchEnabled(boolean)
+         *
+         * @return true if item prefetch is enabled, false otherwise
+         */
+        public final boolean isItemPrefetchEnabled() {
+            return mItemPrefetchEnabled;
+        }
+
+        int getItemPrefetchCount() { return 0; }
+
+        int gatherPrefetchIndices(int dx, int dy, State state, int[] outIndices) {
+            return 0;
+        }
+
         void dispatchAttachedToWindow(RecyclerView view) {
             mIsAttachedToWindow = true;
             onAttachedToWindow(view);
@@ -8118,12 +8328,7 @@
          *                  decoration and margins.
          */
         public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            final Rect insets = lp.mDecorInsets;
-            outBounds.set(view.getLeft() - insets.left - lp.leftMargin,
-                    view.getTop() - insets.top - lp.topMargin,
-                    view.getRight() + insets.right + lp.rightMargin,
-                    view.getBottom() + insets.bottom + lp.bottomMargin);
+            RecyclerView.getDecoratedBoundsWithMarginsInt(view, outBounds);
         }
 
         /**
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
index 12745fe..8e7f307 100644
--- a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -610,8 +610,9 @@
             }
         }
 
-        if (!anchorInfo.mValid || mPendingScrollPosition != NO_POSITION ||
-                mPendingSavedState != null) {
+        boolean recalculateAnchor = !anchorInfo.mValid || mPendingScrollPosition != NO_POSITION ||
+                mPendingSavedState != null;
+        if (recalculateAnchor) {
             anchorInfo.reset();
             if (mPendingSavedState != null) {
                 applyPendingSavedState(anchorInfo);
@@ -619,7 +620,6 @@
                 resolveShouldLayoutReverse();
                 anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
             }
-
             updateAnchorInfoForLayout(state, anchorInfo);
             anchorInfo.mValid = true;
         }
@@ -642,8 +642,18 @@
                     }
                 }
             } else {
-                for (int i = 0; i < mSpanCount; i++) {
-                    mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset);
+                if (recalculateAnchor || mAnchorInfo.mSpanReferenceLines == null) {
+                    for (int i = 0; i < mSpanCount; i++) {
+                        mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout,
+                                anchorInfo.mOffset);
+                    }
+                    mAnchorInfo.saveSpanReferenceLines(mSpans);
+                } else {
+                    for (int i = 0; i < mSpanCount; i++) {
+                        final Span span = mSpans[i];
+                        span.clear();
+                        span.setLine(mAnchorInfo.mSpanReferenceLines[i]);
+                    }
                 }
             }
         }
@@ -1056,8 +1066,8 @@
             return 0;
         }
         return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation,
-                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
-                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
+                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
+                findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
                 this, mSmoothScrollbarEnabled, mShouldReverseLayout);
     }
 
@@ -1076,8 +1086,8 @@
             return 0;
         }
         return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation,
-                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
-                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
+                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
+                findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
                 this, mSmoothScrollbarEnabled);
     }
 
@@ -1096,8 +1106,8 @@
             return 0;
         }
         return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation,
-                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
-                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
+                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
+                findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
                 this, mSmoothScrollbarEnabled);
     }
 
@@ -1250,8 +1260,8 @@
         if (getChildCount() > 0) {
             final AccessibilityRecordCompat record = AccessibilityEventCompat
                     .asRecord(event);
-            final View start = findFirstVisibleItemClosestToStart(false, true);
-            final View end = findFirstVisibleItemClosestToEnd(false, true);
+            final View start = findFirstVisibleItemClosestToStart(false);
+            final View end = findFirstVisibleItemClosestToEnd(false);
             if (start == null || end == null) {
                 return;
             }
@@ -1273,8 +1283,8 @@
      * of returning null.
      */
     int findFirstVisibleItemPositionInt() {
-        final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true, true) :
-                findFirstVisibleItemClosestToStart(true, true);
+        final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true) :
+                findFirstVisibleItemClosestToStart(true);
         return first == null ? NO_POSITION : getPosition(first);
     }
 
@@ -1302,7 +1312,7 @@
      * This method does not do any sorting based on child's start coordinate, instead, it uses
      * children order.
      */
-    View findFirstVisibleItemClosestToStart(boolean fullyVisible, boolean acceptPartiallyVisible) {
+    View findFirstVisibleItemClosestToStart(boolean fullyVisible) {
         final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
         final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
         final int limit = getChildCount();
@@ -1319,7 +1329,7 @@
                 // as long as fully visible is not requested.
                 return child;
             }
-            if (acceptPartiallyVisible && partiallyVisible == null) {
+            if (partiallyVisible == null) {
                 partiallyVisible = child;
             }
         }
@@ -1332,7 +1342,7 @@
      * This method does not do any sorting based on child's end coordinate, instead, it uses
      * children order.
      */
-    View findFirstVisibleItemClosestToEnd(boolean fullyVisible, boolean acceptPartiallyVisible) {
+    View findFirstVisibleItemClosestToEnd(boolean fullyVisible) {
         final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
         final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
         View partiallyVisible = null;
@@ -1348,7 +1358,7 @@
                 // as long as fully visible is not requested.
                 return child;
             }
-            if (acceptPartiallyVisible && partiallyVisible == null) {
+            if (partiallyVisible == null) {
                 partiallyVisible = child;
             }
         }
@@ -2085,6 +2095,8 @@
         mPrimaryOrientation.offsetChildren(-totalScroll);
         // always reset this if we scroll for a proper save instance state
         mLastLayoutFromEnd = mShouldReverseLayout;
+        mLayoutState.mAvailable = 0;
+        recycle(recycler, mLayoutState);
         return totalScroll;
     }
 
@@ -3041,6 +3053,9 @@
         boolean mLayoutFromEnd;
         boolean mInvalidateOffsets;
         boolean mValid;
+        // this is where we save span reference lines in case we need to re-use them for multi-pass
+        // measure steps
+        int[] mSpanReferenceLines;
 
         public AnchorInfo() {
             reset();
@@ -3052,6 +3067,20 @@
             mLayoutFromEnd = false;
             mInvalidateOffsets = false;
             mValid = false;
+            if (mSpanReferenceLines != null) {
+                Arrays.fill(mSpanReferenceLines, -1);
+            }
+        }
+
+        void saveSpanReferenceLines(Span[] spans) {
+            int spanCount = spans.length;
+            if (mSpanReferenceLines == null || mSpanReferenceLines.length < spanCount) {
+                mSpanReferenceLines = new int[mSpans.length];
+            }
+            for (int i = 0; i < spanCount; i++) {
+                // does not matter start or end since this is only recorded when span is reset
+                mSpanReferenceLines[i] = spans[i].getStartLine(Span.INVALID_LINE);
+            }
         }
 
         void assignCoordinateFromPadding() {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
index 34b6621..3a72152 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.view.View;
+import android.view.ViewGroup;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -46,7 +47,7 @@
     }
 
     public RecyclerView setupBasic(Config config, GridTestAdapter testAdapter) throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
+        RecyclerView recyclerView = new WrappedRecyclerView(getActivity());
         mAdapter = testAdapter;
         mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation,
                 config.mReverseLayout);
@@ -149,6 +150,8 @@
 
         CountDownLatch mLayoutLatch;
 
+        CountDownLatch prefetchLatch;
+
         List<GridLayoutManagerTest.Callback>
                 mCallbacks = new ArrayList<GridLayoutManagerTest.Callback>();
 
@@ -227,6 +230,23 @@
             });
         }
 
+        public void expectPrefetch(int count) {
+            prefetchLatch = new CountDownLatch(count);
+        }
+
+        public void waitForPrefetch(int seconds) throws Throwable {
+            prefetchLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+            checkForMainThreadException();
+            MatcherAssert.assertThat("all prefetches should complete on time",
+                    prefetchLatch.getCount(), CoreMatchers.is(0L));
+            // use a runnable to ensure RV layout is finished
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+
         public void expectIdleState(int count) {
             snapLatch = new CountDownLatch(count);
             mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -255,6 +275,12 @@
                 }
             });
         }
+
+        @Override
+        int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+            if (prefetchLatch != null) prefetchLatch.countDown();
+            return super.gatherPrefetchIndices(dx, dy, state, outIndices);
+        }
     }
 
     class GridTestAdapter extends TestAdapter {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
index 353e84e..50c9ba3 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
@@ -345,6 +345,8 @@
 
         CountDownLatch snapLatch;
 
+        CountDownLatch prefetchLatch;
+
         OrientationHelper mSecondaryOrientation;
 
         OnLayoutListener mOnLayoutListener;
@@ -370,6 +372,23 @@
             });
         }
 
+        public void expectPrefetch(int count) {
+            prefetchLatch = new CountDownLatch(count);
+        }
+
+        public void waitForPrefetch(int seconds) throws Throwable {
+            prefetchLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+            checkForMainThreadException();
+            MatcherAssert.assertThat("all prefetches should complete on time",
+                    prefetchLatch.getCount(), CoreMatchers.is(0L));
+            // use a runnable to ensure RV layout is finished
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+
         public void expectIdleState(int count) {
             snapLatch = new CountDownLatch(count);
             mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -576,5 +595,11 @@
             }
             layoutLatch.countDown();
         }
+
+        @Override
+        int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+            if (prefetchLatch != null) prefetchLatch.countDown();
+            return super.gatherPrefetchIndices(dx, dy, state, outIndices);
+        }
     }
 }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 5f7f244..7a7a4d4 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -1107,11 +1107,21 @@
         return Looper.myLooper() == Looper.getMainLooper();
     }
 
-    public void runTestOnUiThread(Runnable r) throws Throwable {
+    public void runTestOnUiThread(final Runnable r) throws Throwable {
         if (Looper.myLooper() == Looper.getMainLooper()) {
             r.run();
         } else {
-            InstrumentationRegistry.getInstrumentation().runOnMainSync(r);
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        r.run();
+                    } catch (Throwable t) {
+                        postExceptionToInstrumentation(t);
+                    }
+                }
+            });
+            checkForMainThreadException();
         }
     }
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
index 82f8cf0..418e5ee 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
@@ -84,8 +84,7 @@
         mRecyclerView = new RecyclerView(getActivity());
         mRecyclerView.setAdapter(mAdapter);
         mRecyclerView.setHasFixedSize(true);
-        mLayoutManager = new WrappedLayoutManager(config.mSpanCount,
-                config.mOrientation);
+        mLayoutManager = new WrappedLayoutManager(config.mSpanCount, config.mOrientation);
         mLayoutManager.setGapStrategy(config.mGapStrategy);
         mLayoutManager.setReverseLayout(config.mReverseLayout);
         mRecyclerView.setLayoutManager(mLayoutManager);
@@ -475,7 +474,7 @@
         // until bug is fixed, we'll fake it.
         // public issue id: 57819
         Boolean mFakeRTL;
-        CountDownLatch snapLatch;
+        CountDownLatch mSnapLatch;
 
         @Override
         boolean isLayoutRTL() {
@@ -500,14 +499,14 @@
         }
 
         public void expectIdleState(int count) {
-            snapLatch = new CountDownLatch(count);
+            mSnapLatch = new CountDownLatch(count);
             mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                 @Override
                 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                     super.onScrollStateChanged(recyclerView, newState);
                     if (newState == RecyclerView.SCROLL_STATE_IDLE) {
-                        snapLatch.countDown();
-                        if (snapLatch.getCount() == 0L) {
+                        mSnapLatch.countDown();
+                        if (mSnapLatch.getCount() == 0L) {
                             mRecyclerView.removeOnScrollListener(this);
                         }
                     }
@@ -516,10 +515,10 @@
         }
 
         public void waitForSnap(int seconds) throws Throwable {
-            snapLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+            mSnapLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
             checkForMainThreadException();
             MatcherAssert.assertThat("all scrolling should complete on time",
-                    snapLatch.getCount(), CoreMatchers.is(0L));
+                    mSnapLatch.getCount(), CoreMatchers.is(0L));
             // use a runnable to ensure RV layout is finished
             getInstrumentation().runOnMainSync(new Runnable() {
                 @Override
@@ -854,6 +853,7 @@
                         / AVG_ITEM_PER_VIEW : mRecyclerViewHeight / AVG_ITEM_PER_VIEW;
             }
             super.onBindViewHolder(holder, position);
+
             Item item = mItems.get(position);
             RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
                     .getLayoutParams();
@@ -862,8 +862,8 @@
                         .setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
             } else {
                 StaggeredGridLayoutManager.LayoutParams slp
-                        = (StaggeredGridLayoutManager.LayoutParams) mLayoutManager
-                        .generateDefaultLayoutParams();
+                    = (StaggeredGridLayoutManager.LayoutParams) mLayoutManager
+                    .generateDefaultLayoutParams();
                 holder.itemView.setLayoutParams(slp);
                 slp.setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
                 lp = slp;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
index 281745c..2dd16ef 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
@@ -501,43 +501,6 @@
         return true;
     }
 
-    static class WrappedRecyclerView extends RecyclerView {
-
-        public WrappedRecyclerView(Context context) {
-            super(context);
-        }
-
-        public void waitUntilLayout() {
-            while (isLayoutRequested()) {
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-
-        public void waitUntilAnimations() throws InterruptedException {
-            final CountDownLatch latch = new CountDownLatch(1);
-            if (mItemAnimator == null || !mItemAnimator.isRunning(
-                    new ItemAnimator.ItemAnimatorFinishedListener() {
-                        @Override
-                        public void onAnimationsFinished() {
-                            latch.countDown();
-                        }
-                    })) {
-                latch.countDown();
-            }
-            MatcherAssert.assertThat("waiting too long for animations",
-                    latch.await(60, TimeUnit.SECONDS), CoreMatchers.is(true));
-        }
-
-        @Override
-        protected void onLayout(boolean changed, int l, int t, int r, int b) {
-            super.onLayout(changed, l, t, r, b);
-        }
-    }
-
     static class WrapContentConfig {
 
         public boolean unlimitedWidth;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
index 4ace4ca..1ebd17f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
@@ -440,13 +440,4 @@
     private interface ThrowingRunnable {
         void run() throws Throwable;
     }
-
-    @Override
-    public void runTestOnUiThread(Runnable r) throws Throwable {
-        if (Looper.myLooper() == Looper.getMainLooper()) {
-            r.run();
-        } else {
-            super.runTestOnUiThread(r);
-        }
-    }
 }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
new file mode 100644
index 0000000..6819a6a
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+public class GridLayoutManagerCacheTest extends BaseGridLayoutManagerTest {
+
+    final Config mConfig;
+    final int mDx;
+    final int mDy;
+
+    public GridLayoutManagerCacheTest(Config config, int dx, int dy) {
+        mConfig = config;
+        mDx = dx;
+        mDy = dy;
+    }
+
+    @Parameterized.Parameters(name = "config:{0}, dx:{1}, dy:{2}")
+    public static List<Object[]> getParams() {
+        List<Object[]> result = new ArrayList<>();
+        List<Config> configs = createBaseVariations();
+        for (Config config : configs) {
+            for (int dx : new int[] {-1, 0, 1}) {
+                for (int dy : new int[] {-1, 0, 1}) {
+                    result.add(new Object[]{config, dx, dy});
+                }
+            }
+        }
+        return result;
+    }
+
+    private ArrayList<RecyclerView.ViewHolder> cachedViews() {
+        return mRecyclerView.mRecycler.mCachedViews;
+    }
+
+    private boolean cachedViewsContains(int position) {
+        // Note: can't make assumptions about order here, so just check all cached views
+        for (int i = 0; i < cachedViews().size(); i++) {
+            if (cachedViews().get(i).getAdapterPosition() == position) return true;
+        }
+        return false;
+    }
+
+    @MediumTest
+    @Test
+    public void cacheAndPrefetch() throws Throwable {
+        final Config config = (Config) mConfig.clone();
+        RecyclerView recyclerView = setupBasic(config);
+        waitForFirstLayout(recyclerView);
+
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // pretend to have an extra 5s before next frame so prefetch won't abort early
+                ((WrappedRecyclerView)mRecyclerView).setDrawingTimeOffset(5000);
+
+                // scroll to the middle, so we can move in either direction
+                mRecyclerView.scrollToPosition(mConfig.mItemCount / 2);
+            }
+        });
+
+        mRecyclerView.setItemViewCacheSize(0);
+        {
+            mGlm.expectPrefetch(1);
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mRecyclerView.mRecycler.recycleAndClearCachedViews();
+                    mRecyclerView.mViewPrefetcher.postFromTraversal(mDx, mDy);
+
+                    // Lie about post time, so prefetch executes even if it is delayed
+                    mRecyclerView.mViewPrefetcher.mPostTimeNanos += TimeUnit.SECONDS.toNanos(5);
+                }
+            });
+            mGlm.waitForPrefetch(1);
+        }
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // validate cache state on UI thread
+                if ((config.mOrientation == HORIZONTAL && mDx == 0)
+                        || (config.mOrientation == VERTICAL && mDy == 0)) {
+                    assertEquals(0, cachedViews().size());
+                } else {
+                    assertEquals(config.mSpanCount, cachedViews().size());
+
+                    boolean reverseScroll = config.mOrientation == HORIZONTAL ? mDx < 0 : mDy < 0;
+                    int lastVisibleItemPosition = mGlm.findLastVisibleItemPosition();
+                    int firstVisibleItemPosition = mGlm.findFirstVisibleItemPosition();
+
+                    for (int i = 0; i < config.mSpanCount; i++) {
+                        if (mConfig.mReverseLayout == reverseScroll) {
+                            // Pos scroll on pos layout, or reverse scroll on reverse layout
+                            // = toward last
+                            assertTrue(cachedViewsContains(lastVisibleItemPosition + 1 + i));
+                        } else {
+                            // Pos scroll on reverse layout, or reverse scroll on pos layout
+                            // = toward first
+                            assertTrue(cachedViewsContains(firstVisibleItemPosition - 1 - i));
+                        }
+                    }
+                }
+            }
+        });
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
index 2b33828..8211fe6 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -29,6 +29,8 @@
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.StateListDrawable;
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -131,7 +133,8 @@
                         stl.addState(new int[]{android.R.attr.state_focused},
                                 new ColorDrawable(Color.RED));
                         stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        testViewHolder.itemView.setBackground(stl);
+                        //noinspection deprecation using this for kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
                         return testViewHolder;
                     }
 
@@ -284,11 +287,13 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     public void horizontalAccessibilitySpanIndices() throws Throwable {
         accessibilitySpanIndicesTest(HORIZONTAL);
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     public void verticalAccessibilitySpanIndices() throws Throwable {
         accessibilitySpanIndicesTest(VERTICAL);
     }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
index 6f77867..1703dcd 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
@@ -27,6 +27,7 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.Gravity;
 import android.view.View;
 
@@ -37,6 +38,7 @@
 import java.util.Arrays;
 import java.util.List;
 
+@MediumTest
 @RunWith(Parameterized.class)
 public class GridLayoutManagerWrapContentTest extends BaseWrapContentTest {
     private boolean mHorizontal = false;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
index d33611c..6c311e4 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
@@ -78,7 +78,7 @@
 
     RecyclerView.LayoutManager mLayoutManager;
 
-    BaseWrapContentTest.WrappedRecyclerView mRecyclerView;
+    WrappedRecyclerView mRecyclerView;
 
     OrientationHelper mHelper;
 
@@ -102,7 +102,7 @@
         }
         mLayoutManager = createFromConfig();
 
-        mRecyclerView = new BaseWrapContentTest.WrappedRecyclerView(getActivity());
+        mRecyclerView = new WrappedRecyclerView(getActivity());
         mHelper = OrientationHelper.createOrientationHelper(
                 mLayoutManager, 1 - mConfig.mOrientation);
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
new file mode 100644
index 0000000..cacc9f4
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.FrameLayout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+public class LinearLayoutManagerCacheTest extends BaseLinearLayoutManagerTest {
+
+    final Config mConfig;
+    final int mDx;
+    final int mDy;
+
+    public LinearLayoutManagerCacheTest(Config config, int dx, int dy) {
+        mConfig = config;
+        mDx = dx;
+        mDy = dy;
+    }
+
+    @Parameterized.Parameters(name = "config:{0}, dx:{1}, dy:{2}")
+    public static List<Object[]> getParams() {
+        List<Object[]> result = new ArrayList<>();
+        List<Config> configs = createBaseVariations();
+        for (Config config : configs) {
+            for (int dx : new int[] {-1, 0, 1}) {
+                for (int dy : new int[] {-1, 0, 1}) {
+                    result.add(new Object[]{config, dx, dy});
+                }
+            }
+        }
+        return result;
+    }
+
+    private ArrayList<RecyclerView.ViewHolder> cachedViews() {
+        return mRecyclerView.mRecycler.mCachedViews;
+    }
+
+    @MediumTest
+    @Test
+    public void cacheAndPrefetch() throws Throwable {
+        final Config config = (Config) mConfig.clone();
+
+        setupByConfig(config, true);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // pretend to have an extra 5s before next frame so prefetch won't abort early
+                ((WrappedRecyclerView)mRecyclerView).setDrawingTimeOffset(5000);
+
+                mRecyclerView.scrollToPosition(100);
+            }
+        });
+
+        mRecyclerView.setItemViewCacheSize(0);
+        {
+            mLayoutManager.expectPrefetch(1);
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mRecyclerView.mRecycler.recycleAndClearCachedViews();
+                    mRecyclerView.mViewPrefetcher.postFromTraversal(mDx, mDy);
+
+                    // Lie about post time, so prefetch executes even if it is delayed
+                    mRecyclerView.mViewPrefetcher.mPostTimeNanos += TimeUnit.SECONDS.toNanos(5);
+                }
+            });
+            mLayoutManager.waitForPrefetch(1);
+        }
+
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // validate cache state on UI thread
+                if ((config.mOrientation == HORIZONTAL && mDx == 0)
+                        || (config.mOrientation == VERTICAL && mDy == 0)) {
+                    assertEquals(0, cachedViews().size());
+                } else {
+                    boolean reverseScroll = config.mOrientation == HORIZONTAL ? mDx < 0 : mDy < 0;
+                    int lastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
+                    int firstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition();
+                    assertEquals(1, cachedViews().size());
+                    int prefetchedPosition = cachedViews().get(0).getAdapterPosition();
+                    if (mConfig.mReverseLayout == reverseScroll) {
+                        // Pos scroll on pos layout, or reverse scroll on reverse layout = toward last
+                        assertEquals(lastVisibleItemPosition + 1, prefetchedPosition);
+                    } else {
+                        // Pos scroll on reverse layout, or reverse scroll on pos layout = toward first
+                        assertEquals(firstVisibleItemPosition - 1, prefetchedPosition);
+                    }
+                }
+            }
+        });
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
index 2bb0750..185aa4b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
@@ -122,8 +122,8 @@
         }
 
         RecyclerView.LayoutManager layoutManager = createFromConfig();
-        BaseWrapContentTest.WrappedRecyclerView
-                recyclerView = new BaseWrapContentTest.WrappedRecyclerView(getActivity());
+        WrappedRecyclerView
+                recyclerView = new WrappedRecyclerView(getActivity());
         recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
         recyclerView.setLayoutManager(layoutManager);
         recyclerView.setLayoutParams(wrapContent);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
index b232271..7079364 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
@@ -309,7 +309,6 @@
         layout();
     }
 
-
     @Test
     public void dontSaveChildrenState() throws InterruptedException {
         MockLayoutManager mlm = new MockLayoutManager() {
@@ -343,6 +342,20 @@
                 loggingView.getOnSavedInstanceCnt());
     }
 
+    @Test
+    public void prefetchChangesCacheSize() {
+        MockLayoutManager mlm = new MockLayoutManager() {
+            @Override
+            int getItemPrefetchCount() {
+                return 3;
+            }
+        };
+        RecyclerView.Recycler recycler = mRecyclerView.mRecycler;
+        assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
+        mRecyclerView.setLayoutManager(mlm);
+        assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax);
+    }
+
     static class MockLayoutManager extends RecyclerView.LayoutManager {
 
         int mLayoutCount = 0;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
index ea1573d..768f2f1 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
@@ -25,6 +25,7 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v7.recyclerview.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -43,6 +44,7 @@
  * represent the same item in the adapter. Keeping a focused view visible is up-to-the
  * LayoutManager and all FW LayoutManagers already have tests for it.
  */
+@MediumTest
 @RunWith(Parameterized.class)
 public class RecyclerViewFocusRecoveryTest extends BaseRecyclerViewInstrumentationTest {
     TestLayoutManager mLayoutManager;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java
new file mode 100644
index 0000000..6b817be
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewPrefetchTest extends BaseRecyclerViewInstrumentationTest {
+    private class PrefetchLayoutManager extends TestLayoutManager {
+        CountDownLatch prefetchLatch = new CountDownLatch(1);
+
+        @Override
+        public boolean canScrollVertically() {
+            return true;
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            super.onLayoutChildren(recycler, state);
+            detachAndScrapAttachedViews(recycler);
+            layoutRange(recycler, 0, 5);
+        }
+
+        @Override
+        public void onLayoutCompleted(RecyclerView.State state) {
+            super.onLayoutCompleted(state);
+            layoutLatch.countDown();
+        }
+
+        @Override
+        int getItemPrefetchCount() {
+            return 1;
+        }
+
+        @Override
+        int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+            prefetchLatch.countDown();
+            outIndices[0] = 6;
+            return 1;
+        }
+
+        void waitForPrefetch(int time) throws InterruptedException {
+            assertThat(prefetchLatch.await(time, TimeUnit.SECONDS),
+                    is(true));
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+    }
+
+    private ArrayList<RecyclerView.ViewHolder> cachedViews() {
+        return mRecyclerView.mRecycler.mCachedViews;
+    }
+
+    @Test
+    public void prefetchTest() throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(new TestAdapter(50));
+        PrefetchLayoutManager layout = new PrefetchLayoutManager();
+        recyclerView.setLayoutManager(layout);
+
+        {
+            layout.expectLayouts(1);
+            setRecyclerView(recyclerView);
+            layout.waitForLayout(10);
+        }
+
+        assertThat(layout.prefetchLatch.getCount(), is(1L)); // shouldn't have fired yet
+        assertThat(cachedViews().size(), is(0));
+        smoothScrollBy(50);
+
+        layout.waitForPrefetch(10);
+        assertThat(cachedViews().size(), is(1));
+        assertThat(cachedViews().get(0).getAdapterPosition(), is(6));
+    }
+}
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
index f8d11d8..71484dd 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
@@ -304,9 +304,9 @@
                 final String boundsLog = mLayoutManager.getBoundsLog();
                 VisibleChildren queryResult = new VisibleChildren(mLayoutManager.getSpanCount());
                 queryResult.findFirstPartialVisibleClosestToStart = mLayoutManager
-                        .findFirstVisibleItemClosestToStart(false, true);
+                        .findFirstVisibleItemClosestToStart(false);
                 queryResult.findFirstPartialVisibleClosestToEnd = mLayoutManager
-                        .findFirstVisibleItemClosestToEnd(false, true);
+                        .findFirstVisibleItemClosestToEnd(false);
                 queryResult.firstFullyVisiblePositions = mLayoutManager
                         .findFirstCompletelyVisibleItemPositions(
                                 provideArr ? new int[mLayoutManager.getSpanCount()] : null);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
index d4955d5..51b469d 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
@@ -62,6 +62,46 @@
 
     @MediumTest
     @Test
+    public void snapOnScrollSameViewFixedSize() throws Throwable {
+        // This test is a special case for fixed sized children.
+        final Config config = ((Config) mConfig.clone()).itemCount(10);
+        setupByConfig(config);
+        RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(1000, 950);
+        mRecyclerView.setLayoutParams(lp);
+        mAdapter.mOnBindCallback = new OnBindCallback() {
+            @Override
+            void onBoundItem(TestViewHolder vh, int position) {
+                StaggeredGridLayoutManager.LayoutParams slp = getLayoutParamsForPosition(position);
+                vh.itemView.setLayoutParams(slp);
+            }
+
+            @Override
+            boolean assignRandomSize() {
+                return false;
+            }
+        };
+        waitFirstLayout();
+        setupSnapHelper();
+
+        // Record the current center view.
+        View view = findCenterView(mLayoutManager);
+        assertCenterAligned(view);
+        // This number comes from the sizes of the fixed views that are created for this config/
+        // See getLayoutParamsForPosition(int) below. Obtained manually.
+        int scrollDistance = mLayoutManager.canScrollHorizontally() ? 52 : 52;
+        int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
+        mLayoutManager.expectIdleState(2);
+        smoothScrollBy(scrollDist);
+        mLayoutManager.waitForSnap(10);
+
+        // Views have not changed
+        View viewAfterScroll = findCenterView(mLayoutManager);
+        assertSame("The view should NOT have scrolled", view, viewAfterScroll);
+        assertCenterAligned(viewAfterScroll);
+    }
+
+    @MediumTest
+    @Test
     public void snapOnScrollSameView() throws Throwable {
         final Config config = (Config) mConfig.clone();
         setupByConfig(config);
@@ -71,18 +111,18 @@
         // Record the current center view.
         View view = findCenterView(mLayoutManager);
         assertCenterAligned(view);
-        // For a staggered grid layout manager we need to keep the distance
+        // For a staggered grid layout manager with unknown item size we need to keep the distance
         // small enough to ensure we do not scroll over to an offset view in a different span.
-        int scrollDistance = 5;
+        int scrollDistance = findMinSafeScrollDistance();
         int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
         mLayoutManager.expectIdleState(2);
         smoothScrollBy(scrollDist);
         mLayoutManager.waitForSnap(10);
 
         // Views have not changed
-        View viewAfterFling = findCenterView(mLayoutManager);
-        assertSame("The view should have scrolled", view, viewAfterFling);
-        assertCenterAligned(viewAfterFling);
+        View viewAfterScroll = findCenterView(mLayoutManager);
+        assertSame("The view should NOT have scrolled", view, viewAfterScroll);
+        assertCenterAligned(viewAfterScroll);
     }
 
     @Test
@@ -163,6 +203,21 @@
         assertCenterAligned(viewAfterFling);
     }
 
+    private StaggeredGridLayoutManager.LayoutParams getLayoutParamsForPosition(int position) {
+        // Only enabled fixed sizes if the config says so.
+        if (mLayoutManager.canScrollHorizontally()) {
+            int width = 400 + position * 70;
+            return new StaggeredGridLayoutManager.LayoutParams(width, 300);
+        } else {
+            int height = 300 + position * 70;
+            return new StaggeredGridLayoutManager.LayoutParams(300, height);
+        }
+    }
+
+    @Nullable View findCenterView(RecyclerView.LayoutManager layoutManager) {
+        return mLayoutManager.findFirstVisibleItemClosestToCenter();
+    }
+
     private void setupSnapHelper() throws Throwable {
         SnapHelper snapHelper = new LinearSnapHelper();
         mLayoutManager.expectIdleState(1);
@@ -174,7 +229,11 @@
         mLayoutManager.waitForLayout(2);
 
         View view = findCenterView(mLayoutManager);
-        int scrollDistance = (getViewDimension(view) / 2) + 10;
+        int scrollDistance = distFromCenter(view) / 2;
+        if (scrollDistance == 0) {
+            return;
+        }
+
         int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
 
         mLayoutManager.expectIdleState(2);
@@ -182,10 +241,6 @@
         mLayoutManager.waitForSnap(10);
     }
 
-    @Nullable View findCenterView(RecyclerView.LayoutManager layoutManager) {
-        return mLayoutManager.findFirstVisibleItemClosestToCenter();
-    }
-
     private int getViewDimension(View view) {
         OrientationHelper helper;
         if (mLayoutManager.canScrollHorizontally()) {
@@ -206,6 +261,28 @@
         }
     }
 
+    private int findMinSafeScrollDistance() {
+        int minDist = Integer.MAX_VALUE;
+        for (int i = mLayoutManager.getChildCount() - 1; i >= 0; i--) {
+            final View child = mLayoutManager.getChildAt(i);
+            int dist = distFromCenter(child);
+            if (dist < minDist) {
+                minDist = dist;
+            }
+        }
+        return minDist / 2 - 1;
+    }
+
+    private int distFromCenter(View view) {
+        if (mLayoutManager.canScrollHorizontally()) {
+            return Math.abs(mRecyclerView.getWidth() / 2 -
+                    mLayoutManager.getViewBounds(view).centerX());
+        } else {
+            return Math.abs(mRecyclerView.getHeight() / 2 -
+                    mLayoutManager.getViewBounds(view).centerY());
+        }
+    }
+
     private boolean fling(final int velocityX, final int velocityY)
             throws Throwable {
         final AtomicBoolean didStart = new AtomicBoolean(false);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
index e6e202c..18cae23 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
@@ -135,17 +135,17 @@
         assertEquals("last completely visible item from span 1 should be 1", 1, into[1]);
         assertEquals("first fully visible child should be at position",
                 0, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToStart(true, true)).getPosition());
+                        findFirstVisibleItemClosestToStart(true)).getPosition());
         assertEquals("last fully visible child should be at position",
                 4, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToEnd(true, true)).getPosition());
+                        findFirstVisibleItemClosestToEnd(true)).getPosition());
 
         assertEquals("first visible child should be at position",
                 0, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToStart(false, true)).getPosition());
+                        findFirstVisibleItemClosestToStart(false)).getPosition());
         assertEquals("last visible child should be at position",
                 4, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToEnd(false, true)).getPosition());
+                        findFirstVisibleItemClosestToEnd(false)).getPosition());
 
     }
 
@@ -323,7 +323,8 @@
                         stl.addState(new int[]{android.R.attr.state_focused},
                                 new ColorDrawable(Color.RED));
                         stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        testViewHolder.itemView.setBackground(stl);
+                        //noinspection deprecation used to support kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
                         return testViewHolder;
                     }
 
@@ -681,9 +682,15 @@
         smoothScrollToPosition(mAdapter.getItemCount() / 2);
         final int changePosition = mAdapter.getItemCount() / 4;
         mLayoutManager.expectLayouts(1);
-        mAdapter.changeAndNotify(changePosition, 1);
-        mLayoutManager.assertNoLayout("no layout should happen when an invisible child is updated",
-                1);
+        if (RecyclerView.POST_UPDATES_ON_ANIMATION) {
+            mAdapter.changeAndNotify(changePosition, 1);
+            mLayoutManager.assertNoLayout("no layout should happen when an invisible child is "
+                    + "updated", 1);
+        } else {
+            mAdapter.changeAndNotify(changePosition, 1);
+            mLayoutManager.waitForLayout(1);
+        }
+
         // delete an item before visible area
         int deletedPosition = mLayoutManager.getPosition(mLayoutManager.getChildAt(0)) - 2;
         assertTrue("test sanity", deletedPosition >= 0);
@@ -800,10 +807,10 @@
                 .asRecord(event);
         final int start = mRecyclerView
                 .getChildLayoutPosition(
-                        mLayoutManager.findFirstVisibleItemClosestToStart(false, true));
+                        mLayoutManager.findFirstVisibleItemClosestToStart(false));
         final int end = mRecyclerView
                 .getChildLayoutPosition(
-                        mLayoutManager.findFirstVisibleItemClosestToEnd(false, true));
+                        mLayoutManager.findFirstVisibleItemClosestToEnd(false));
         assertEquals("first item position should match",
                 Math.min(start, end), record.getFromIndex());
         assertEquals("last item position should match",
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
index 5e07dca..5021ecb 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.Gravity;
 import android.view.View;
 
@@ -35,6 +36,7 @@
 import java.util.Arrays;
 import java.util.List;
 
+@MediumTest
 @RunWith(Parameterized.class)
 public class StaggeredGridLayoutManagerWrapContentTest extends BaseWrapContentTest {
     int mOrientation = StaggeredGridLayoutManager.VERTICAL;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java b/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
index 1f0f3ef..b0f90d6 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
@@ -25,8 +25,12 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import android.graphics.Rect;
+import android.support.annotation.NonNull;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.Toast;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -44,33 +48,44 @@
 @MediumTest
 @RunWith(Parameterized.class)
 public class TestResizingRelayoutWithAutoMeasure extends BaseRecyclerViewInstrumentationTest {
+    private final int mRvWidth;
+    private final int mRvHeight;
     private final RecyclerView.LayoutManager mLayoutManager;
     private final float mWidthMultiplier;
     private final float mHeightMultiplier;
 
     public TestResizingRelayoutWithAutoMeasure(@SuppressWarnings("UnusedParameters") String name,
+            int rvWidth, int rvHeight,
             RecyclerView.LayoutManager layoutManager, float widthMultiplier,
             float heightMultiplier) {
+        mRvWidth = rvWidth;
+        mRvHeight = rvHeight;
         mLayoutManager = layoutManager;
         mWidthMultiplier = widthMultiplier;
         mHeightMultiplier = heightMultiplier;
     }
 
-    @Parameterized.Parameters(name = "{0} w:{2} h:{3}")
+    @Parameterized.Parameters(name = "{0} rv w/h:{1}/{2} changed w/h:{4}/{5}")
     public static List<Object[]> getParams() {
         List<Object[]> params = new ArrayList<>();
-        for (float w : new float[]{.5f, 1f, 2f}) {
-            for (float h : new float[]{.5f, 1f, 2f}) {
-                params.add(
-                        new Object[]{"linear layout", new LinearLayoutManager(null), w, h}
-                );
-                params.add(
-                        new Object[]{"grid layout", new GridLayoutManager(null, 3), w, h}
-                );
-                params.add(
-                        new Object[]{"staggered", new StaggeredGridLayoutManager(3,
-                                StaggeredGridLayoutManager.VERTICAL), w, h}
-                );
+        for(int[] rvSize : new int[][]{new int[]{200, 200}, new int[]{200, 100},
+                new int[]{100, 200}}) {
+            for (float w : new float[]{.5f, 1f, 2f}) {
+                for (float h : new float[]{.5f, 1f, 2f}) {
+                    params.add(
+                            new Object[]{"linear layout", rvSize[0], rvSize[1],
+                                    new LinearLayoutManager(null), w, h}
+                    );
+                    params.add(
+                            new Object[]{"grid layout", rvSize[0], rvSize[1],
+                                    new GridLayoutManager(null, 3), w, h}
+                    );
+                    params.add(
+                            new Object[]{"staggered", rvSize[0], rvSize[1],
+                                    new StaggeredGridLayoutManager(3,
+                                    StaggeredGridLayoutManager.VERTICAL), w, h}
+                    );
+                }
             }
         }
         return params;
@@ -78,9 +93,12 @@
 
     @Test
     public void testResizeDuringMeasurements() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity());
         recyclerView.setLayoutManager(mLayoutManager);
-        recyclerView.setAdapter(new TestAdapter(500));
+        StaticAdapter adapter = new StaticAdapter(50, ViewGroup.LayoutParams.MATCH_PARENT,
+                mRvHeight / 5);
+        recyclerView.setLayoutParams(new FrameLayout.LayoutParams(mRvWidth, mRvHeight));
+        recyclerView.setAdapter(adapter);
         setRecyclerView(recyclerView);
         getInstrumentation().waitForIdleSync();
         assertThat("Test sanity", recyclerView.getChildCount() > 0, is(true));
@@ -88,38 +106,57 @@
         smoothScrollToPosition(lastPosition);
         assertThat("test sanity", recyclerView.findViewHolderForAdapterPosition(lastPosition),
                 notNullValue());
+        assertThat("test sanity", mRvWidth, is(recyclerView.getWidth()));
+        assertThat("test sanity", mRvHeight, is(recyclerView.getHeight()));
+        recyclerView.waitUntilLayout();
+        recyclerView.waitUntilAnimations();
+        final Map<Integer, Rect> startPositions = capturePositions(recyclerView);
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                int startHeight = recyclerView.getMeasuredHeight();
-                int startWidth = recyclerView.getMeasuredWidth();
-                Map<Integer, Rect> startPositions = capturePositions(recyclerView);
                 recyclerView.measure(
-                        makeMeasureSpec((int) (startWidth * mWidthMultiplier),
+                        makeMeasureSpec((int) (mRvWidth * mWidthMultiplier),
                                 mWidthMultiplier == 1f ? EXACTLY : AT_MOST),
-                        makeMeasureSpec((int) (startHeight * mHeightMultiplier),
+                        makeMeasureSpec((int) (mRvHeight * mHeightMultiplier),
                                 mHeightMultiplier == 1f ? EXACTLY : AT_MOST));
 
                 recyclerView.measure(
-                        makeMeasureSpec(startWidth, EXACTLY),
-                        makeMeasureSpec(startHeight, EXACTLY));
+                        makeMeasureSpec(mRvWidth, EXACTLY),
+                        makeMeasureSpec(mRvHeight, EXACTLY));
                 recyclerView.dispatchLayout();
                 Map<Integer, Rect> endPositions = capturePositions(recyclerView);
                 assertStartItemPositions(startPositions, endPositions);
             }
         });
+        recyclerView.waitUntilLayout();
+        recyclerView.waitUntilAnimations();
+        checkForMainThreadException();
     }
 
     private void assertStartItemPositions(Map<Integer, Rect> startPositions,
             Map<Integer, Rect> endPositions) {
+        String log = log(startPositions, endPositions);
         for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
             Rect rect = endPositions.get(entry.getKey());
-            assertThat("view for position " + entry.getKey() + " at" + entry.getValue(), rect,
+            assertThat(log + "view for position " + entry.getKey() + " at" + entry.getValue(), rect,
                     notNullValue());
-            assertThat("rect for position " + entry.getKey(), entry.getValue(), is(rect));
+            assertThat(log + "rect for position " + entry.getKey(), entry.getValue(), is(rect));
         }
     }
 
+    @NonNull
+    private String log(Map<Integer, Rect> startPositions, Map<Integer, Rect> endPositions) {
+        StringBuilder logBuilder = new StringBuilder();
+        for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
+            logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
+        }
+        logBuilder.append("------\n");
+        for (Map.Entry<Integer, Rect> entry : endPositions.entrySet()) {
+            logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
+        }
+        return logBuilder.toString();
+    }
+
     private Map<Integer, Rect> capturePositions(RecyclerView recyclerView) {
         Map<Integer, Rect> positions = new HashMap<>();
         for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
@@ -138,4 +175,52 @@
         }
         return positions;
     }
+
+    private class StaticAdapter extends RecyclerView.Adapter<TestViewHolder> {
+        final int mSize;
+        // is passed to the layout params of the item
+        final int mMinItemWidth;
+        final int mMinItemHeight;
+
+        public StaticAdapter(int size, int minItemWidth, int minItemHeight) {
+            mSize = size;
+            mMinItemWidth = minItemWidth;
+            mMinItemHeight = minItemHeight;
+        }
+
+        @Override
+        public TestViewHolder onCreateViewHolder(ViewGroup parent,
+                int viewType) {
+            return new TestViewHolder(new View(parent.getContext()));
+        }
+
+        @Override
+        public void onBindViewHolder(TestViewHolder holder, int position) {
+            holder.mBoundItem = new Item(position, "none");
+            if (mMinItemHeight < 1 && mMinItemWidth < 1) {
+                return;
+            }
+            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+            if (lp == null) {
+                lp = new ViewGroup.LayoutParams(0, 0);
+            }
+            if (mMinItemWidth > 0) {
+                lp.width = (int) (mMinItemWidth + (position % 10) * mMinItemWidth / 7f);
+            } else {
+                lp.width = mMinItemWidth;
+            }
+
+            if (mMinItemHeight > 0) {
+                lp.height = (int) (mMinItemHeight + (position % 10) * mMinItemHeight / 7f);
+            } else {
+                lp.height = mMinItemHeight;
+            }
+            holder.itemView.setLayoutParams(lp);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mSize;
+        }
+    }
 }
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
index b485fa6..b0e6613 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
@@ -26,6 +26,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.Display;
 import android.view.View;
 import android.view.ViewGroup;
@@ -40,6 +41,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class WrapContentBasicTest extends AndroidTestCase {
 
@@ -200,6 +202,63 @@
             return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT);
         }
+
+        // START MOCKITO OVERRIDES
+        // We override package protected methods to make them public. This is necessary to run
+        // mockito on Kitkat
+        @Override
+        public void setRecyclerView(RecyclerView recyclerView) {
+            super.setRecyclerView(recyclerView);
+        }
+
+        @Override
+        public void dispatchAttachedToWindow(RecyclerView view) {
+            super.dispatchAttachedToWindow(view);
+        }
+
+        @Override
+        public void dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+            super.dispatchDetachedFromWindow(view, recycler);
+        }
+
+        @Override
+        public void setExactMeasureSpecsFrom(RecyclerView recyclerView) {
+            super.setExactMeasureSpecsFrom(recyclerView);
+        }
+
+        @Override
+        public void setMeasureSpecs(int wSpec, int hSpec) {
+            super.setMeasureSpecs(wSpec, hSpec);
+        }
+
+        @Override
+        public void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
+            super.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
+        }
+
+        @Override
+        public boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec,
+                RecyclerView.LayoutParams lp) {
+            return super.shouldReMeasureChild(child, widthSpec, heightSpec, lp);
+        }
+
+        @Override
+        public boolean shouldMeasureChild(View child, int widthSpec, int heightSpec,
+                RecyclerView.LayoutParams lp) {
+            return super.shouldMeasureChild(child, widthSpec, heightSpec, lp);
+        }
+
+        @Override
+        public void removeAndRecycleScrapInt(RecyclerView.Recycler recycler) {
+            super.removeAndRecycleScrapInt(recycler);
+        }
+
+        @Override
+        public void stopSmoothScroller() {
+            super.stopSmoothScroller();
+        }
+
+        // END MOCKITO OVERRIDES
     }
 
     public class WrapAdapter extends RecyclerView.Adapter {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
index 1da3ba5..58a0841 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
@@ -16,10 +16,18 @@
 
 package android.support.v7.widget;
 
+import android.app.Instrumentation;
 import android.content.Context;
+import android.support.test.InstrumentationRegistry;
 import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * RecyclerView wrapper used in tests. This class can fake behavior like layout direction w/o
  * playing with framework support.
@@ -27,11 +35,21 @@
 public class WrappedRecyclerView extends RecyclerView {
 
     Boolean mFakeRTL;
+    private long mDrawingTimeOffsetMs;
 
     public void setFakeRTL(Boolean fakeRTL) {
         mFakeRTL = fakeRTL;
     }
 
+    public void setDrawingTimeOffset(long offsetMs) {
+        mDrawingTimeOffsetMs = offsetMs;
+    }
+
+    @Override
+    public long getDrawingTime() {
+        return super.getDrawingTime() + mDrawingTimeOffsetMs;
+    }
+
     public WrappedRecyclerView(Context context) {
         super(context);
         init(context);
@@ -51,6 +69,34 @@
         //initializeScrollbars(null);
     }
 
+    public void waitUntilLayout() {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        while (isLayoutRequested()) {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void waitUntilAnimations() throws InterruptedException {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        final CountDownLatch latch = new CountDownLatch(1);
+        if (mItemAnimator == null || !mItemAnimator.isRunning(
+                new ItemAnimator.ItemAnimatorFinishedListener() {
+                    @Override
+                    public void onAnimationsFinished() {
+                        latch.countDown();
+                    }
+                })) {
+            latch.countDown();
+        }
+        MatcherAssert.assertThat("waiting too long for animations",
+                latch.await(60, TimeUnit.SECONDS), CoreMatchers.is(true));
+    }
+
+
     @Override
     public int getLayoutDirection() {
         if (mFakeRTL == null) {