Avoid absolute path loading .so after M am: 405f6d6e7c am: 5ab545784d
am: 4c2f5b63e9

* commit '4c2f5b63e935777645bb819b5e261ad5dda1796d':
  Avoid absolute path loading .so after M
diff --git a/.gitignore b/.gitignore
index c8c3ed8..a72b3dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,5 @@
 project.properties
 **/bin
 **/gen
+*.iml
+**/out
diff --git a/Android.mk b/Android.mk
index 4abc112..8fd0693b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,8 +23,15 @@
 .PHONY: update-support-api
 .PHONY: check-support-api
 
+.PHONY: support-gradle-archive
+support-gradle-archive: PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
+support-gradle-archive:
+	$(PRIVATE_LOCAL_PATH)/gradlew -p $(PRIVATE_LOCAL_PATH) createArchive
+
 # Run the check-support-api task on a SDK build
 sdk: check-support-api
+# Run the support-gradle-archive task on a SDK build
+sdk: support-gradle-archive
 
 # Build all support libraries
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/apicheck.mk b/apicheck.mk
index 1638607..739cfb3 100644
--- a/apicheck.mk
+++ b/apicheck.mk
@@ -20,6 +20,7 @@
 # $(support_module_java_libraries) - dependent libraries
 # $(support_module_java_packages) - list of package names containing public classes
 # $(support_module_src_files) - list of source files
+# $(support_module_aidl_includes) - list of aidl files
 # $(api_check_current_msg_file) - file containing error message for current API check
 # $(api_check_last_msg_file) - file containing error message for last SDK API check
 # ---------------------------------------------
@@ -39,6 +40,7 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(support_module_src_files)
+LOCAL_AIDL_INCLUDES := $(support_module_aidl_includes)
 LOCAL_JAVA_LIBRARIES := $(support_module_java_libraries)
 LOCAL_ADDITIONAL_JAVA_DIR := \
     $(call intermediates-dir-for,$(LOCAL_MODULE_CLASS),$(support_module),,COMMON)/src
@@ -117,6 +119,7 @@
 support_module :=
 support_module_api_dir :=
 support_module_src_files :=
+support_module_aidl_includes :=
 support_module_java_libraries :=
 support_module_java_packages :=
 support_module_api_file :=
diff --git a/build.gradle b/build.gradle
index 6a90344..3b23406 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,8 +9,8 @@
     }
 }
 
-ext.supportVersion = '23.0.1'
-ext.extraVersion = 19
+ext.supportVersion = '23.2.0-SNAPSHOT'
+ext.extraVersion = 25
 ext.supportRepoOut = ''
 ext.buildToolsVersion = '22.1.0'
 ext.buildNumber = Integer.toString(ext.extraVersion)
@@ -34,6 +34,7 @@
 }
 
 ext.supportRepoOut = new File(buildDir, 'support_repo')
+ext.testApkDistOut = new File(buildDir, 'test_apks')
 
 // Main task called by the build server.
 task(createArchive) << {
@@ -170,6 +171,17 @@
     }
 }
 
+project.gradle.buildFinished { buildResult ->
+    if (buildResult.getFailure() != null) {
+        println()
+        println 'Build failed. Possible causes include:'
+        println '    1) Bad codes'
+        println '    2) Out of date prebuilts in prebuilts/sdk'
+        println '    3) Need to update the compileSdkVersion in a library\'s build.gradle'
+        println()
+    }
+}
+
 FileCollection getAndroidPrebuilt(String apiLevel) {
     files("$rootDir/../../prebuilts/sdk/$apiLevel/android.jar")
 }
diff --git a/customtabs/api/23.txt b/customtabs/api/23.0.0.txt
similarity index 100%
rename from customtabs/api/23.txt
rename to customtabs/api/23.0.0.txt
diff --git a/customtabs/api/23.1.0.txt b/customtabs/api/23.1.0.txt
new file mode 100644
index 0000000..caa5ea4b
--- /dev/null
+++ b/customtabs/api/23.1.0.txt
@@ -0,0 +1,88 @@
+package android.support.customtabs {
+
+  public class CustomTabsCallback {
+    ctor public CustomTabsCallback();
+    method public void extraCallback(java.lang.String, android.os.Bundle);
+    method public void onNavigationEvent(int, android.os.Bundle);
+    field public static final int NAVIGATION_ABORTED = 4; // 0x4
+    field public static final int NAVIGATION_FAILED = 3; // 0x3
+    field public static final int NAVIGATION_FINISHED = 2; // 0x2
+    field public static final int NAVIGATION_STARTED = 1; // 0x1
+    field public static final int TAB_HIDDEN = 6; // 0x6
+    field public static final int TAB_SHOWN = 5; // 0x5
+  }
+
+  public class CustomTabsClient {
+    method public static boolean bindCustomTabsService(android.content.Context, java.lang.String, android.support.customtabs.CustomTabsServiceConnection);
+    method public android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+    method public android.support.customtabs.CustomTabsSession newSession(android.support.customtabs.CustomTabsCallback);
+    method public boolean warmup(long);
+  }
+
+  public final class CustomTabsIntent {
+    method public void launchUrl(android.app.Activity, android.net.Uri);
+    field public static final java.lang.String EXTRA_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
+    field public static final java.lang.String EXTRA_CLOSE_BUTTON_ICON = "android.support.customtabs.extra.CLOSE_BUTTON_ICON";
+    field public static final java.lang.String EXTRA_ENABLE_URLBAR_HIDING = "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
+    field public static final java.lang.String EXTRA_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
+    field public static final java.lang.String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
+    field public static final java.lang.String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
+    field public static final java.lang.String EXTRA_TINT_ACTION_BUTTON = "android.support.customtabs.extra.TINT_ACTION_BUTTON";
+    field public static final java.lang.String EXTRA_TITLE_VISIBILITY_STATE = "android.support.customtabs.extra.TITLE_VISIBILITY";
+    field public static final java.lang.String EXTRA_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR";
+    field public static final java.lang.String KEY_DESCRIPTION = "android.support.customtabs.customaction.DESCRIPTION";
+    field public static final java.lang.String KEY_ICON = "android.support.customtabs.customaction.ICON";
+    field public static final java.lang.String KEY_MENU_ITEM_TITLE = "android.support.customtabs.customaction.MENU_ITEM_TITLE";
+    field public static final java.lang.String KEY_PENDING_INTENT = "android.support.customtabs.customaction.PENDING_INTENT";
+    field public static final int NO_TITLE = 0; // 0x0
+    field public static final int SHOW_PAGE_TITLE = 1; // 0x1
+    field public final android.content.Intent intent;
+    field public final android.os.Bundle startAnimationBundle;
+  }
+
+  public static final class CustomTabsIntent.Builder {
+    ctor public CustomTabsIntent.Builder();
+    ctor public CustomTabsIntent.Builder(android.support.customtabs.CustomTabsSession);
+    method public android.support.customtabs.CustomTabsIntent.Builder addMenuItem(java.lang.String, android.app.PendingIntent);
+    method public android.support.customtabs.CustomTabsIntent build();
+    method public android.support.customtabs.CustomTabsIntent.Builder enableUrlBarHiding();
+    method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent, boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent);
+    method public android.support.customtabs.CustomTabsIntent.Builder setCloseButtonIcon(android.graphics.Bitmap);
+    method public android.support.customtabs.CustomTabsIntent.Builder setExitAnimations(android.content.Context, int, int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setShowTitle(boolean);
+    method public android.support.customtabs.CustomTabsIntent.Builder setStartAnimations(android.content.Context, int, int);
+    method public android.support.customtabs.CustomTabsIntent.Builder setToolbarColor(int);
+  }
+
+  public abstract class CustomTabsService extends android.app.Service {
+    ctor public CustomTabsService();
+    method protected boolean cleanUpSession(android.support.customtabs.CustomTabsSessionToken);
+    method protected abstract android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+    method protected abstract boolean mayLaunchUrl(android.support.customtabs.CustomTabsSessionToken, android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+    method protected abstract boolean newSession(android.support.customtabs.CustomTabsSessionToken);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method protected abstract boolean updateVisuals(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle);
+    method protected abstract boolean warmup(long);
+    field public static final java.lang.String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
+    field public static final java.lang.String KEY_URL = "android.support.customtabs.otherurls.URL";
+  }
+
+  public abstract class CustomTabsServiceConnection implements android.content.ServiceConnection {
+    ctor public CustomTabsServiceConnection();
+    method public abstract void onCustomTabsServiceConnected(android.content.ComponentName, android.support.customtabs.CustomTabsClient);
+    method public final void onServiceConnected(android.content.ComponentName, android.os.IBinder);
+  }
+
+  public final class CustomTabsSession {
+    method public boolean mayLaunchUrl(android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+    method public boolean setActionButton(android.graphics.Bitmap, java.lang.String);
+  }
+
+  public class CustomTabsSessionToken {
+    method public android.support.customtabs.CustomTabsCallback getCallback();
+    method public static android.support.customtabs.CustomTabsSessionToken getSessionTokenFromIntent(android.content.Intent);
+  }
+
+}
+
diff --git a/customtabs/api/current.txt b/customtabs/api/current.txt
index b66c71e..caa5ea4b 100644
--- a/customtabs/api/current.txt
+++ b/customtabs/api/current.txt
@@ -8,6 +8,8 @@
     field public static final int NAVIGATION_FAILED = 3; // 0x3
     field public static final int NAVIGATION_FINISHED = 2; // 0x2
     field public static final int NAVIGATION_STARTED = 1; // 0x1
+    field public static final int TAB_HIDDEN = 6; // 0x6
+    field public static final int TAB_SHOWN = 5; // 0x5
   }
 
   public class CustomTabsClient {
@@ -21,9 +23,11 @@
     method public void launchUrl(android.app.Activity, android.net.Uri);
     field public static final java.lang.String EXTRA_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
     field public static final java.lang.String EXTRA_CLOSE_BUTTON_ICON = "android.support.customtabs.extra.CLOSE_BUTTON_ICON";
+    field public static final java.lang.String EXTRA_ENABLE_URLBAR_HIDING = "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
     field public static final java.lang.String EXTRA_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
     field public static final java.lang.String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
     field public static final java.lang.String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
+    field public static final java.lang.String EXTRA_TINT_ACTION_BUTTON = "android.support.customtabs.extra.TINT_ACTION_BUTTON";
     field public static final java.lang.String EXTRA_TITLE_VISIBILITY_STATE = "android.support.customtabs.extra.TITLE_VISIBILITY";
     field public static final java.lang.String EXTRA_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR";
     field public static final java.lang.String KEY_DESCRIPTION = "android.support.customtabs.customaction.DESCRIPTION";
@@ -41,6 +45,8 @@
     ctor public CustomTabsIntent.Builder(android.support.customtabs.CustomTabsSession);
     method public android.support.customtabs.CustomTabsIntent.Builder addMenuItem(java.lang.String, android.app.PendingIntent);
     method public android.support.customtabs.CustomTabsIntent build();
+    method public android.support.customtabs.CustomTabsIntent.Builder enableUrlBarHiding();
+    method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent, boolean);
     method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent);
     method public android.support.customtabs.CustomTabsIntent.Builder setCloseButtonIcon(android.graphics.Bitmap);
     method public android.support.customtabs.CustomTabsIntent.Builder setExitAnimations(android.content.Context, int, int);
@@ -56,6 +62,7 @@
     method protected abstract boolean mayLaunchUrl(android.support.customtabs.CustomTabsSessionToken, android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
     method protected abstract boolean newSession(android.support.customtabs.CustomTabsSessionToken);
     method public android.os.IBinder onBind(android.content.Intent);
+    method protected abstract boolean updateVisuals(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle);
     method protected abstract boolean warmup(long);
     field public static final java.lang.String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
     field public static final java.lang.String KEY_URL = "android.support.customtabs.otherurls.URL";
@@ -69,6 +76,7 @@
 
   public final class CustomTabsSession {
     method public boolean mayLaunchUrl(android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+    method public boolean setActionButton(android.graphics.Bitmap, java.lang.String);
   }
 
   public class CustomTabsSessionToken {
diff --git a/customtabs/src/android/support/customtabs/CustomTabsCallback.java b/customtabs/src/android/support/customtabs/CustomTabsCallback.java
index ea5f3e3..d7fdd39 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsCallback.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsCallback.java
@@ -44,6 +44,16 @@
     public static final int NAVIGATION_ABORTED = 4;
 
     /**
+     * Sent when the tab becomes visible.
+     */
+    public static final int TAB_SHOWN = 5;
+
+    /**
+     * Sent when the tab becomes hidden.
+     */
+    public static final int TAB_HIDDEN = 6;
+
+    /**
      * To be called when a navigation event happens.
      *
      * @param navigationEvent The code corresponding to the navigation event.
diff --git a/customtabs/src/android/support/customtabs/CustomTabsIntent.java b/customtabs/src/android/support/customtabs/CustomTabsIntent.java
index 2276f94..ab3685f 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsIntent.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsIntent.java
@@ -57,6 +57,12 @@
             "android.support.customtabs.extra.TOOLBAR_COLOR";
 
     /**
+     * Boolean extra that enables the url bar to hide as the user scrolls down the page
+     */
+    public static final String EXTRA_ENABLE_URLBAR_HIDING =
+            "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
+
+    /**
      * Extra bitmap that specifies the icon of the back button on the toolbar. If the client chooses
      * not to customize it, a default close button will be used.
      */
@@ -109,6 +115,13 @@
             "android.support.customtabs.customaction.PENDING_INTENT";
 
     /**
+     * Extra boolean that specifies whether the custom action button should be tinted. Default is
+     * false and the action button will not be tinted.
+     */
+    public static final String EXTRA_TINT_ACTION_BUTTON =
+            "android.support.customtabs.extra.TINT_ACTION_BUTTON";
+
+    /**
      * Use an {@code ArrayList<Bundle>} for specifying menu related params. There should be a
      * separate {@link Bundle} for each custom menu item.
      */
@@ -202,6 +215,14 @@
         }
 
         /**
+         * Enables the url bar to hide as the user scrolls down on the page.
+         */
+        public Builder enableUrlBarHiding() {
+            mIntent.putExtra(EXTRA_ENABLE_URLBAR_HIDING, true);
+            return this;
+        }
+
+        /**
          * Sets the Close button icon for the custom tab.
          *
          * @param icon The icon {@link Bitmap}
@@ -243,18 +264,29 @@
          * @param icon The icon.
          * @param description The description for the button. To be used for accessibility.
          * @param pendingIntent pending intent delivered when the button is clicked.
+         * @param shouldTint Whether the action button should be tinted.
          */
-        public Builder setActionButton(@NonNull Bitmap icon,
-                @NonNull String description, @NonNull PendingIntent pendingIntent) {
+        public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
+                @NonNull PendingIntent pendingIntent, boolean shouldTint) {
             Bundle bundle = new Bundle();
             bundle.putParcelable(KEY_ICON, icon);
             bundle.putString(KEY_DESCRIPTION, description);
             bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent);
             mIntent.putExtra(EXTRA_ACTION_BUTTON_BUNDLE, bundle);
+            mIntent.putExtra(EXTRA_TINT_ACTION_BUTTON, shouldTint);
             return this;
         }
 
         /**
+         * See {@link CustomTabsIntent.Builder#setActionButton(
+         * Bitmap, String, PendingIntent, boolean)}
+         */
+        public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
+                @NonNull PendingIntent pendingIntent) {
+            return setActionButton(icon, description, pendingIntent, false);
+        }
+
+        /**
          * Sets the start animations,
          *
          * @param context Application context.
diff --git a/customtabs/src/android/support/customtabs/CustomTabsService.java b/customtabs/src/android/support/customtabs/CustomTabsService.java
index 37f1a60..25697c5 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsService.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsService.java
@@ -50,7 +50,7 @@
      public static final String KEY_URL =
              "android.support.customtabs.otherurls.URL";
 
-     private Map<IBinder, DeathRecipient> mDeathRecipientMap = new ArrayMap<>();
+     private final Map<IBinder, DeathRecipient> mDeathRecipientMap = new ArrayMap<>();
 
      private ICustomTabsService.Stub mBinder = new ICustomTabsService.Stub() {
 
@@ -90,6 +90,12 @@
          public Bundle extraCommand(String commandName, Bundle args) {
              return CustomTabsService.this.extraCommand(commandName, args);
          }
+
+         @Override
+         public boolean updateVisuals(ICustomTabsCallback callback, Bundle bundle) {
+             return CustomTabsService.this.updateVisuals(
+                     new CustomTabsSessionToken(callback), bundle);
+         }
      };
 
      @Override
@@ -176,4 +182,15 @@
       * @return The result {@link Bundle}, or null.
       */
      protected abstract Bundle extraCommand(String commandName, Bundle args);
+
+    /**
+     * Updates the visuals of custom tabs for the given session. Will only succeed if the given
+     * session matches the currently active one.
+     * @param sessionToken The currently active session that the custom tab belongs to.
+     * @param bundle       The action button configuration bundle. This bundle should be constructed
+     *                     with the same structure in {@link CustomTabsIntent.Builder}.
+     * @return Whether the operation was successful.
+     */
+     protected abstract boolean updateVisuals(CustomTabsSessionToken sessionToken,
+             Bundle bundle);
  }
diff --git a/customtabs/src/android/support/customtabs/CustomTabsSession.java b/customtabs/src/android/support/customtabs/CustomTabsSession.java
index ee45b7c..a51cf0e 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsSession.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsSession.java
@@ -17,10 +17,12 @@
 package android.support.customtabs;
 
 import android.content.ComponentName;
+import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.support.annotation.NonNull;
 
 import java.util.List;
 
@@ -65,6 +67,27 @@
         }
     }
 
+    /**
+     * Update the visuals for the button on a custom tab. Will only succeed if the given
+     * session is the active one in browser.
+     * @param icon          The new icon of the action button.
+     * @param description   Content description of the action button.
+     * @return              Whether the update succeeded.
+     */
+    public boolean setActionButton(@NonNull Bitmap icon, @NonNull String description) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(CustomTabsIntent.KEY_ICON, icon);
+        bundle.putString(CustomTabsIntent.KEY_DESCRIPTION, description);
+
+        Bundle metaBundle = new Bundle();
+        metaBundle.putBundle(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE, bundle);
+        try {
+            return mService.updateVisuals(mCallback, metaBundle);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     /* package */ IBinder getBinder() {
         return mCallback.asBinder();
     }
@@ -72,4 +95,4 @@
     /* package */ ComponentName getComponentName() {
         return mComponentName;
     }
-}
\ No newline at end of file
+}
diff --git a/customtabs/src/android/support/customtabs/ICustomTabsService.aidl b/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
index 2565928..e53ca84 100644
--- a/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
+++ b/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
@@ -32,4 +32,5 @@
     boolean mayLaunchUrl(in ICustomTabsCallback callback, in Uri url,
             in Bundle extras, in List<Bundle> otherLikelyBundles) = 3;
     Bundle extraCommand(String commandName, in Bundle args) = 4;
+    boolean updateVisuals(in ICustomTabsCallback callback, in Bundle bundle) = 5;
 }
diff --git a/design/Android.mk b/design/Android.mk
index 0b0b2a8..6f4ac3b 100644
--- a/design/Android.mk
+++ b/design/Android.mk
@@ -23,13 +23,17 @@
 LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := $(call all-java-files-under, dummy)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
-    frameworks/support/v7/appcompat/res
+    frameworks/support/v7/appcompat/res \
+    frameworks/support/v7/recyclerview/res
 LOCAL_AAPT_FLAGS := \
     --auto-add-overlay \
-    --extra-packages android.support.v7.appcompat
+    --extra-packages android.support.v7.appcompat \
+    --extra-packages android.support.v7.recyclerview
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files := $(LOCAL_SRC_FILES)
+
 # A helper sub-library to resolve cyclic dependencies between src and the platform dependent
 # implementations
 include $(CLEAR_VARS)
@@ -38,9 +42,12 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, base)
 LOCAL_JAVA_LIBRARIES := android-support-design-res \
     android-support-v4 \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of Eclair MR1 APIs
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-design-eclair-mr1
@@ -49,9 +56,12 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-base
 LOCAL_JAVA_LIBRARIES := android-support-design-res \
     android-support-v4 \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of Honeycomb APIs
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-design-honeycomb
@@ -60,9 +70,12 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-eclair-mr1
 LOCAL_JAVA_LIBRARIES := android-support-design-res \
     android-support-v4 \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of Honeycomb MR1 APIs
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-design-honeycomb-mr1
@@ -71,20 +84,40 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb
 LOCAL_JAVA_LIBRARIES := android-support-design-res \
     android-support-v4 \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
+# A helper sub-library that makes direct use of ICS APIs
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-design-ics
+LOCAL_SDK_VERSION := 14
+LOCAL_SRC_FILES := $(call all-java-files-under, ics)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb-mr1
+LOCAL_JAVA_LIBRARIES := android-support-design-res \
+    android-support-v4 \
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of Lollipop APIs
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-design-lollipop
 LOCAL_SDK_VERSION := 21
 LOCAL_SRC_FILES := $(call all-java-files-under, lollipop)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb-mr1
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-ics
 LOCAL_JAVA_LIBRARIES := android-support-design-res \
     android-support-v4 \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # Here is the final static library that apps can link against.
 # The R class is automatically excluded from the generated library.
 # Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -96,14 +129,16 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-lollipop
 LOCAL_JAVA_LIBRARIES := android-support-design-res \
     android-support-v4 \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-recyclerview
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # API Check
 # ---------------------------------------------
 support_module := $(LOCAL_MODULE)
 support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
 support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
 support_module_java_packages := android.support.design.*
 include $(SUPPORT_API_CHECK)
diff --git a/design/api/23.txt b/design/api/23.0.0.txt
similarity index 100%
rename from design/api/23.txt
rename to design/api/23.0.0.txt
diff --git a/design/api/23.1.0.txt b/design/api/23.1.0.txt
new file mode 100644
index 0000000..f68ab1b
--- /dev/null
+++ b/design/api/23.1.0.txt
@@ -0,0 +1,420 @@
+package android.support.design.widget {
+
+  public class AppBarLayout extends android.widget.LinearLayout {
+    ctor public AppBarLayout(android.content.Context);
+    ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
+    method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+    method public float getTargetElevation();
+    method public final int getTotalScrollRange();
+    method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+    method public void setExpanded(boolean);
+    method public void setExpanded(boolean, boolean);
+    method public void setTargetElevation(float);
+  }
+
+  public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
+    ctor public AppBarLayout.Behavior();
+    ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, float, float, boolean);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int);
+    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
+    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View);
+    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
+  }
+
+  public static abstract class AppBarLayout.Behavior.DragCallback {
+    ctor public AppBarLayout.Behavior.DragCallback();
+    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
+  }
+
+  protected static class AppBarLayout.Behavior.SavedState extends android.view.View.BaseSavedState {
+    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
+  }
+
+  public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
+    ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public AppBarLayout.LayoutParams(int, int);
+    ctor public AppBarLayout.LayoutParams(int, int, float);
+    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
+    ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
+    method public int getScrollFlags();
+    method public android.view.animation.Interpolator getScrollInterpolator();
+    method public void setScrollFlags(int);
+    method public void setScrollInterpolator(android.view.animation.Interpolator);
+    field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
+    field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
+    field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
+    field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
+    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
+  }
+
+  public static abstract interface AppBarLayout.OnOffsetChangedListener {
+    method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
+  }
+
+  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
+    ctor public AppBarLayout.ScrollingViewBehavior();
+    ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+    method public int getOverlayTop();
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
+    method public void setOverlayTop(int);
+  }
+
+  public class CollapsingToolbarLayout extends android.widget.FrameLayout {
+    ctor public CollapsingToolbarLayout(android.content.Context);
+    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
+    method public int getCollapsedTitleGravity();
+    method public android.graphics.Typeface getCollapsedTitleTypeface();
+    method public android.graphics.drawable.Drawable getContentScrim();
+    method public int getExpandedTitleGravity();
+    method public android.graphics.Typeface getExpandedTitleTypeface();
+    method public android.graphics.drawable.Drawable getStatusBarScrim();
+    method public java.lang.CharSequence getTitle();
+    method public boolean isTitleEnabled();
+    method public void setCollapsedTitleGravity(int);
+    method public void setCollapsedTitleTextAppearance(int);
+    method public void setCollapsedTitleTextColor(int);
+    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
+    method public void setContentScrim(android.graphics.drawable.Drawable);
+    method public void setContentScrimColor(int);
+    method public void setContentScrimResource(int);
+    method public void setExpandedTitleColor(int);
+    method public void setExpandedTitleGravity(int);
+    method public void setExpandedTitleTextAppearance(int);
+    method public void setExpandedTitleTypeface(android.graphics.Typeface);
+    method public void setScrimsShown(boolean);
+    method public void setScrimsShown(boolean, boolean);
+    method public void setStatusBarScrim(android.graphics.drawable.Drawable);
+    method public void setStatusBarScrimColor(int);
+    method public void setStatusBarScrimResource(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleEnabled(boolean);
+  }
+
+  public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public CollapsingToolbarLayout.LayoutParams(int, int);
+    ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    method public int getCollapseMode();
+    method public float getParallaxMultiplier();
+    method public void setCollapseMode(int);
+    method public void setParallaxMultiplier(float);
+    field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
+    field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
+    field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
+  }
+
+  public class CoordinatorLayout extends android.view.ViewGroup {
+    ctor public CoordinatorLayout(android.content.Context);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void dispatchDependentViewsChanged(android.view.View);
+    method public boolean doViewsOverlap(android.view.View, android.view.View);
+    method public java.util.List<android.view.View> getDependencies(android.view.View);
+    method public android.graphics.drawable.Drawable getStatusBarBackground();
+    method public boolean isPointInChildBounds(android.view.View, int, int);
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onLayoutChild(android.view.View, int);
+    method public void onMeasureChild(android.view.View, int, int, int, int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackgroundColor(int);
+    method public void setStatusBarBackgroundResource(int);
+  }
+
+  public static abstract class CoordinatorLayout.Behavior {
+    ctor public CoordinatorLayout.Behavior();
+    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
+    method public final int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
+    method public final float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
+    method public static java.lang.Object getTag(android.view.View);
+    method public boolean isDirty(android.support.design.widget.CoordinatorLayout, V);
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
+    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public static void setTag(android.view.View, java.lang.Object);
+  }
+
+  public static abstract class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
+  }
+
+  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public CoordinatorLayout.LayoutParams(int, int);
+    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    method public int getAnchorId();
+    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+    method public void setAnchorId(int);
+    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
+    field public int anchorGravity;
+    field public int gravity;
+    field public int keyline;
+  }
+
+  protected static class CoordinatorLayout.SavedState extends android.view.View.BaseSavedState {
+    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
+  }
+
+  public class FloatingActionButton extends android.widget.ImageButton {
+    ctor public FloatingActionButton(android.content.Context);
+    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
+    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
+    method public void hide();
+    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+    method public void setRippleColor(int);
+    method public void show();
+    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+  }
+
+  public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public FloatingActionButton.Behavior();
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
+  }
+
+  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
+    ctor public FloatingActionButton.OnVisibilityChangedListener();
+    method public void onHidden(android.support.design.widget.FloatingActionButton);
+    method public void onShown(android.support.design.widget.FloatingActionButton);
+  }
+
+   abstract class HeaderBehavior extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderBehavior();
+    ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
+  }
+
+   abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderScrollingViewBehavior();
+    ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+  }
+
+  public class NavigationView extends android.widget.FrameLayout {
+    ctor public NavigationView(android.content.Context);
+    ctor public NavigationView(android.content.Context, android.util.AttributeSet);
+    ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
+    method public void addHeaderView(android.view.View);
+    method public android.graphics.drawable.Drawable getItemBackground();
+    method public android.content.res.ColorStateList getItemIconTintList();
+    method public android.content.res.ColorStateList getItemTextColor();
+    method public android.view.Menu getMenu();
+    method public android.view.View inflateHeaderView(int);
+    method public void inflateMenu(int);
+    method public void removeHeaderView(android.view.View);
+    method public void setCheckedItem(int);
+    method public void setItemBackground(android.graphics.drawable.Drawable);
+    method public void setItemBackgroundResource(int);
+    method public void setItemIconTintList(android.content.res.ColorStateList);
+    method public void setItemTextAppearance(int);
+    method public void setItemTextColor(android.content.res.ColorStateList);
+    method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
+  }
+
+  public static abstract interface NavigationView.OnNavigationItemSelectedListener {
+    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+  }
+
+  public static class NavigationView.SavedState extends android.view.View.BaseSavedState {
+    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public NavigationView.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
+    field public android.os.Bundle menuState;
+  }
+
+  public final class Snackbar {
+    method public void dismiss();
+    method public int getDuration();
+    method public android.view.View getView();
+    method public boolean isShown();
+    method public boolean isShownOrQueued();
+    method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
+    method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
+    method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
+    method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
+    method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
+    method public android.support.design.widget.Snackbar setActionTextColor(int);
+    method public android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
+    method public android.support.design.widget.Snackbar setDuration(int);
+    method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
+    method public android.support.design.widget.Snackbar setText(int);
+    method public void show();
+    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
+    field public static final int LENGTH_LONG = 0; // 0x0
+    field public static final int LENGTH_SHORT = -1; // 0xffffffff
+  }
+
+  public static abstract class Snackbar.Callback {
+    ctor public Snackbar.Callback();
+    method public void onDismissed(android.support.design.widget.Snackbar, int);
+    method public void onShown(android.support.design.widget.Snackbar);
+    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
+    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
+    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
+    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
+    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
+  }
+
+  public class SwipeDismissBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public SwipeDismissBehavior();
+    method public int getDragState();
+    method public void setDragDismissDistance(float);
+    method public void setEndAlphaSwipeDistance(float);
+    method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
+    method public void setSensitivity(float);
+    method public void setStartAlphaSwipeDistance(float);
+    method public void setSwipeDirection(int);
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+    field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
+    field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
+    field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
+  }
+
+  public static abstract interface SwipeDismissBehavior.OnDismissListener {
+    method public abstract void onDismiss(android.view.View);
+    method public abstract void onDragStateChanged(int);
+  }
+
+  public class TabLayout extends android.widget.HorizontalScrollView {
+    ctor public TabLayout(android.content.Context);
+    ctor public TabLayout(android.content.Context, android.util.AttributeSet);
+    ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void addTab(android.support.design.widget.TabLayout.Tab);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, int);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
+    method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
+    method public int getSelectedTabPosition();
+    method public android.support.design.widget.TabLayout.Tab getTabAt(int);
+    method public int getTabCount();
+    method public int getTabGravity();
+    method public int getTabMode();
+    method public android.content.res.ColorStateList getTabTextColors();
+    method public android.support.design.widget.TabLayout.Tab newTab();
+    method public void removeAllTabs();
+    method public void removeTab(android.support.design.widget.TabLayout.Tab);
+    method public void removeTabAt(int);
+    method public void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+    method public void setScrollPosition(int, float, boolean);
+    method public void setSelectedTabIndicatorColor(int);
+    method public void setSelectedTabIndicatorHeight(int);
+    method public void setTabGravity(int);
+    method public void setTabMode(int);
+    method public void setTabTextColors(android.content.res.ColorStateList);
+    method public void setTabTextColors(int, int);
+    method public void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
+    method public void setupWithViewPager(android.support.v4.view.ViewPager);
+    field public static final int GRAVITY_CENTER = 1; // 0x1
+    field public static final int GRAVITY_FILL = 0; // 0x0
+    field public static final int MODE_FIXED = 1; // 0x1
+    field public static final int MODE_SCROLLABLE = 0; // 0x0
+  }
+
+  public static abstract interface TabLayout.OnTabSelectedListener {
+    method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
+    method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
+    method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+  }
+
+  public static final class TabLayout.Tab {
+    method public java.lang.CharSequence getContentDescription();
+    method public android.view.View getCustomView();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public int getPosition();
+    method public java.lang.Object getTag();
+    method public java.lang.CharSequence getText();
+    method public boolean isSelected();
+    method public void select();
+    method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
+    method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
+    method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
+    method public android.support.design.widget.TabLayout.Tab setCustomView(int);
+    method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
+    method public android.support.design.widget.TabLayout.Tab setIcon(int);
+    method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
+    method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
+    method public android.support.design.widget.TabLayout.Tab setText(int);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+    ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
+    method public void onPageScrollStateChanged(int);
+    method public void onPageScrolled(int, float, int);
+    method public void onPageSelected(int);
+  }
+
+  public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
+    ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
+    method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
+    method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
+    method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+  }
+
+  public class TextInputLayout extends android.widget.LinearLayout {
+    ctor public TextInputLayout(android.content.Context);
+    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
+    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
+    method public int getCounterMaxLength();
+    method public android.widget.EditText getEditText();
+    method public java.lang.CharSequence getError();
+    method public java.lang.CharSequence getHint();
+    method public android.graphics.Typeface getTypeface();
+    method public boolean isErrorEnabled();
+    method public boolean isHintAnimationEnabled();
+    method public void setCounterEnabled(boolean);
+    method public void setCounterMaxLength(int);
+    method public void setError(java.lang.CharSequence);
+    method public void setErrorEnabled(boolean);
+    method public void setHint(java.lang.CharSequence);
+    method public void setHintAnimationEnabled(boolean);
+    method public void setHintTextAppearance(int);
+    method public void setTypeface(android.graphics.Typeface);
+  }
+
+   class ViewOffsetBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public ViewOffsetBehavior();
+    ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
+    method public int getLeftAndRightOffset();
+    method public int getTopAndBottomOffset();
+    method public boolean setLeftAndRightOffset(int);
+    method public boolean setTopAndBottomOffset(int);
+  }
+
+}
+
diff --git a/design/api/current.txt b/design/api/current.txt
index de4e09b..7d85b1b 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -12,10 +12,9 @@
     method public void setTargetElevation(float);
   }
 
-  public static class AppBarLayout.Behavior extends android.support.design.widget.ViewOffsetBehavior {
+  public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
     ctor public AppBarLayout.Behavior();
     ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.MotionEvent);
     method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
     method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, float, float, boolean);
     method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[]);
@@ -24,11 +23,16 @@
     method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
     method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int);
     method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View);
-    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.MotionEvent);
+    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
+  }
+
+  public static abstract class AppBarLayout.Behavior.DragCallback {
+    ctor public AppBarLayout.Behavior.DragCallback();
+    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
   }
 
   protected static class AppBarLayout.Behavior.SavedState extends android.view.View.BaseSavedState {
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel);
+    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
     ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
     field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
   }
@@ -49,41 +53,77 @@
     field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
     field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
     field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
+    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
   }
 
   public static abstract interface AppBarLayout.OnOffsetChangedListener {
     method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
   }
 
-  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
     ctor public AppBarLayout.ScrollingViewBehavior();
     ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
     method public int getOverlayTop();
     method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
     method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
     method public void setOverlayTop(int);
   }
 
+  public class BottomSheetBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+    ctor public BottomSheetBehavior();
+    ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
+    method public static android.support.design.widget.BottomSheetBehavior<V> from(V);
+    method public final int getPeekHeight();
+    method public final int getState();
+    method public final void setPeekHeight(int);
+    method public final void setState(int);
+    field public static final int STATE_COLLAPSED = 4; // 0x4
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_EXPANDED = 3; // 0x3
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  protected static class BottomSheetBehavior.SavedState extends android.view.View.BaseSavedState {
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
+    ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
+  }
+
   public class CollapsingToolbarLayout extends android.widget.FrameLayout {
     ctor public CollapsingToolbarLayout(android.content.Context);
     ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
     ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
     method public int getCollapsedTitleGravity();
+    method public android.graphics.Typeface getCollapsedTitleTypeface();
     method public android.graphics.drawable.Drawable getContentScrim();
     method public int getExpandedTitleGravity();
+    method public int getExpandedTitleMarginBottom();
+    method public int getExpandedTitleMarginEnd();
+    method public int getExpandedTitleMarginStart();
+    method public int getExpandedTitleMarginTop();
+    method public android.graphics.Typeface getExpandedTitleTypeface();
     method public android.graphics.drawable.Drawable getStatusBarScrim();
     method public java.lang.CharSequence getTitle();
     method public boolean isTitleEnabled();
     method public void setCollapsedTitleGravity(int);
     method public void setCollapsedTitleTextAppearance(int);
     method public void setCollapsedTitleTextColor(int);
+    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
     method public void setContentScrim(android.graphics.drawable.Drawable);
     method public void setContentScrimColor(int);
     method public void setContentScrimResource(int);
     method public void setExpandedTitleColor(int);
     method public void setExpandedTitleGravity(int);
+    method public void setExpandedTitleMargin(int, int, int, int);
+    method public void setExpandedTitleMarginBottom(int);
+    method public void setExpandedTitleMarginEnd(int);
+    method public void setExpandedTitleMarginStart(int);
+    method public void setExpandedTitleMarginTop(int);
     method public void setExpandedTitleTextAppearance(int);
+    method public void setExpandedTitleTypeface(android.graphics.Typeface);
+    method public void setScrimsShown(boolean);
+    method public void setScrimsShown(boolean, boolean);
     method public void setStatusBarScrim(android.graphics.drawable.Drawable);
     method public void setStatusBarScrimColor(int);
     method public void setStatusBarScrimResource(int);
@@ -173,33 +213,59 @@
   }
 
   protected static class CoordinatorLayout.SavedState extends android.view.View.BaseSavedState {
-    ctor public CoordinatorLayout.SavedState(android.os.Parcel);
+    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
     ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
     field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
   }
 
-  public class FloatingActionButton extends android.widget.ImageView {
+  public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
     ctor public FloatingActionButton(android.content.Context);
     ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
     ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
+    method public android.graphics.drawable.Drawable getContentBackground();
+    method public boolean getContentRect(android.graphics.Rect);
+    method public float getFloatingActionButtonElevation();
+    method public boolean getUseCompatPadding();
     method public void hide();
+    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+    method public void setFloatingActionButtonElevation(float);
     method public void setRippleColor(int);
+    method public void setUseCompatPadding(boolean);
     method public void show();
+    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
   }
 
   public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
     ctor public FloatingActionButton.Behavior();
     method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
     method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
-    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
     method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
   }
 
+  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
+    ctor public FloatingActionButton.OnVisibilityChangedListener();
+    method public void onHidden(android.support.design.widget.FloatingActionButton);
+    method public void onShown(android.support.design.widget.FloatingActionButton);
+  }
+
+   abstract class HeaderBehavior extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderBehavior();
+    ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
+  }
+
+   abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+    ctor public HeaderScrollingViewBehavior();
+    ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+  }
+
   public class NavigationView extends android.widget.FrameLayout {
     ctor public NavigationView(android.content.Context);
     ctor public NavigationView(android.content.Context, android.util.AttributeSet);
     ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
     method public void addHeaderView(android.view.View);
+    method public int getHeaderCount();
+    method public android.view.View getHeaderView(int);
     method public android.graphics.drawable.Drawable getItemBackground();
     method public android.content.res.ColorStateList getItemIconTintList();
     method public android.content.res.ColorStateList getItemTextColor();
@@ -221,7 +287,7 @@
   }
 
   public static class NavigationView.SavedState extends android.view.View.BaseSavedState {
-    ctor public NavigationView.SavedState(android.os.Parcel);
+    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
     ctor public NavigationView.SavedState(android.os.Parcelable);
     field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
     field public android.os.Bundle menuState;
@@ -232,6 +298,7 @@
     method public int getDuration();
     method public android.view.View getView();
     method public boolean isShown();
+    method public boolean isShownOrQueued();
     method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
     method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
     method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
@@ -261,6 +328,7 @@
 
   public class SwipeDismissBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
     ctor public SwipeDismissBehavior();
+    method public boolean canSwipeDismissView(android.view.View);
     method public int getDragState();
     method public void setDragDismissDistance(float);
     method public void setEndAlphaSwipeDistance(float);
@@ -307,7 +375,7 @@
     method public void setTabMode(int);
     method public void setTabTextColors(android.content.res.ColorStateList);
     method public void setTabTextColors(int, int);
-    method public void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
+    method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
     method public void setupWithViewPager(android.support.v4.view.ViewPager);
     field public static final int GRAVITY_CENTER = 1; // 0x1
     field public static final int GRAVITY_FILL = 0; // 0x0
@@ -360,15 +428,22 @@
     ctor public TextInputLayout(android.content.Context);
     ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
     ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
+    method public int getCounterMaxLength();
     method public android.widget.EditText getEditText();
     method public java.lang.CharSequence getError();
     method public java.lang.CharSequence getHint();
+    method public android.graphics.Typeface getTypeface();
+    method public boolean isCounterEnabled();
     method public boolean isErrorEnabled();
     method public boolean isHintAnimationEnabled();
+    method public boolean isHintEnabled();
+    method public void setCounterEnabled(boolean);
+    method public void setCounterMaxLength(int);
     method public void setError(java.lang.CharSequence);
     method public void setErrorEnabled(boolean);
     method public void setHint(java.lang.CharSequence);
     method public void setHintAnimationEnabled(boolean);
+    method public void setHintEnabled(boolean);
     method public void setHintTextAppearance(int);
     method public void setTypeface(android.graphics.Typeface);
   }
@@ -382,5 +457,11 @@
     method public boolean setTopAndBottomOffset(int);
   }
 
+   class VisibilityAwareImageButton extends android.widget.ImageButton {
+    ctor public VisibilityAwareImageButton(android.content.Context);
+    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
 }
 
diff --git a/design/base/android/support/design/widget/AnimationUtils.java b/design/base/android/support/design/widget/AnimationUtils.java
index a7854f5..8ef1722 100644
--- a/design/base/android/support/design/widget/AnimationUtils.java
+++ b/design/base/android/support/design/widget/AnimationUtils.java
@@ -16,7 +16,9 @@
 
 package android.support.design.widget;
 
+import android.support.v4.view.animation.FastOutLinearInInterpolator;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.support.v4.view.animation.LinearOutSlowInInterpolator;
 import android.view.animation.Animation;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -26,6 +28,8 @@
 
     static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
     static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
+    static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new FastOutLinearInInterpolator();
+    static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR = new LinearOutSlowInInterpolator();
     static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
 
     /**
diff --git a/design/base/android/support/design/widget/CircularBorderDrawable.java b/design/base/android/support/design/widget/CircularBorderDrawable.java
index ff57777..617a501 100644
--- a/design/base/android/support/design/widget/CircularBorderDrawable.java
+++ b/design/base/android/support/design/widget/CircularBorderDrawable.java
@@ -16,6 +16,7 @@
 
 package android.support.design.widget;
 
+import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.LinearGradient;
@@ -50,10 +51,13 @@
     private int mBottomOuterStrokeColor;
     private int mBottomInnerStrokeColor;
 
-    private int mTintColor;
+    private ColorStateList mBorderTint;
+    private int mCurrentBorderTintColor;
 
     private boolean mInvalidateShader = true;
 
+    private float mRotation;
+
     public CircularBorderDrawable() {
         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mPaint.setStyle(Paint.Style.STROKE);
@@ -98,8 +102,11 @@
         rectF.right -= halfBorderWidth;
         rectF.bottom -= halfBorderWidth;
 
+        canvas.save();
+        canvas.rotate(mRotation, rectF.centerX(), rectF.centerY());
         // Draw the oval
         canvas.drawOval(rectF, mPaint);
+        canvas.restore();
     }
 
     @Override
@@ -115,8 +122,11 @@
         invalidateSelf();
     }
 
-    void setTintColor(int tintColor) {
-        mTintColor = tintColor;
+    void setBorderTint(ColorStateList tint) {
+        if (tint != null) {
+            mCurrentBorderTintColor = tint.getColorForState(getState(), mCurrentBorderTintColor);
+        }
+        mBorderTint = tint;
         mInvalidateShader = true;
         invalidateSelf();
     }
@@ -132,11 +142,38 @@
         return mBorderWidth > 0 ? PixelFormat.TRANSLUCENT : PixelFormat.TRANSPARENT;
     }
 
+    final void setRotation(float rotation) {
+        if (rotation != mRotation) {
+            mRotation = rotation;
+            invalidateSelf();
+        }
+    }
+
     @Override
     protected void onBoundsChange(Rect bounds) {
         mInvalidateShader = true;
     }
 
+    @Override
+    public boolean isStateful() {
+        return (mBorderTint != null && mBorderTint.isStateful()) || super.isStateful();
+    }
+
+    @Override
+    protected boolean onStateChange(int[] state) {
+        if (mBorderTint != null) {
+            final int newColor = mBorderTint.getColorForState(state, mCurrentBorderTintColor);
+            if (newColor != mCurrentBorderTintColor) {
+                mInvalidateShader = true;
+                mCurrentBorderTintColor = newColor;
+            }
+        }
+        if (mInvalidateShader) {
+            invalidateSelf();
+        }
+        return mInvalidateShader;
+    }
+
     /**
      * Creates a vertical {@link LinearGradient}
      * @return
@@ -148,14 +185,14 @@
         final float borderRatio = mBorderWidth / rect.height();
 
         final int[] colors = new int[6];
-        colors[0] = ColorUtils.compositeColors(mTopOuterStrokeColor, mTintColor);
-        colors[1] = ColorUtils.compositeColors(mTopInnerStrokeColor, mTintColor);
+        colors[0] = ColorUtils.compositeColors(mTopOuterStrokeColor, mCurrentBorderTintColor);
+        colors[1] = ColorUtils.compositeColors(mTopInnerStrokeColor, mCurrentBorderTintColor);
         colors[2] = ColorUtils.compositeColors(
-                ColorUtils.setAlphaComponent(mTopInnerStrokeColor, 0), mTintColor);
+                ColorUtils.setAlphaComponent(mTopInnerStrokeColor, 0), mCurrentBorderTintColor);
         colors[3] = ColorUtils.compositeColors(
-                ColorUtils.setAlphaComponent(mBottomInnerStrokeColor, 0), mTintColor);
-        colors[4] = ColorUtils.compositeColors(mBottomInnerStrokeColor, mTintColor);
-        colors[5] = ColorUtils.compositeColors(mBottomOuterStrokeColor, mTintColor);
+                ColorUtils.setAlphaComponent(mBottomInnerStrokeColor, 0), mCurrentBorderTintColor);
+        colors[4] = ColorUtils.compositeColors(mBottomInnerStrokeColor, mCurrentBorderTintColor);
+        colors[5] = ColorUtils.compositeColors(mBottomOuterStrokeColor, mCurrentBorderTintColor);
 
         final float[] positions = new float[6];
         positions[0] = 0f;
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 969e570..189060a 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -18,13 +18,30 @@
 
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.PorterDuff;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.support.annotation.Nullable;
 import android.support.design.R;
-import android.view.View;
+import android.view.ViewTreeObserver;
 
 abstract class FloatingActionButtonImpl {
 
+    Drawable mShapeDrawable;
+    Drawable mRippleDrawable;
+    CircularBorderDrawable mBorderDrawable;
+    Drawable mContentBackground;
+
+    float mElevation;
+    float mPressedTranslationZ;
+
+    interface InternalVisibilityChangedListener {
+        public void onShown();
+        public void onHidden();
+    }
+
     static final int SHOW_HIDE_ANIM_DURATION = 200;
 
     static final int[] PRESSED_ENABLED_STATE_SET = {android.R.attr.state_pressed,
@@ -33,15 +50,19 @@
             android.R.attr.state_enabled};
     static final int[] EMPTY_STATE_SET = new int[0];
 
-    final View mView;
+    final VisibilityAwareImageButton mView;
     final ShadowViewDelegate mShadowViewDelegate;
 
-    FloatingActionButtonImpl(View view, ShadowViewDelegate shadowViewDelegate) {
+    private final Rect mTmpRect = new Rect();
+    private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
+
+    FloatingActionButtonImpl(VisibilityAwareImageButton view,
+            ShadowViewDelegate shadowViewDelegate) {
         mView = view;
         mShadowViewDelegate = shadowViewDelegate;
     }
 
-    abstract void setBackgroundDrawable(Drawable originalBackground, ColorStateList backgroundTint,
+    abstract void setBackgroundDrawable(ColorStateList backgroundTint,
             PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth);
 
     abstract void setBackgroundTintList(ColorStateList tint);
@@ -50,19 +71,70 @@
 
     abstract void setRippleColor(int rippleColor);
 
-    abstract void setElevation(float elevation);
+    final void setElevation(float elevation) {
+        if (mElevation != elevation) {
+            mElevation = elevation;
+            onElevationChanged(elevation);
+        }
+    }
 
-    abstract void setPressedTranslationZ(float translationZ);
+    abstract float getElevation();
+
+    final void setPressedTranslationZ(float translationZ) {
+        if (mPressedTranslationZ != translationZ) {
+            mPressedTranslationZ = translationZ;
+            onTranslationZChanged(translationZ);
+        }
+    }
+
+    abstract void onElevationChanged(float elevation);
+
+    abstract void onTranslationZChanged(float translationZ);
 
     abstract void onDrawableStateChanged(int[] state);
 
     abstract void jumpDrawableToCurrentState();
 
-    abstract void hide();
+    abstract void hide(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
 
-    abstract void show();
+    abstract void show(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
 
-    Drawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
+    final Drawable getContentBackground() {
+        return mContentBackground;
+    }
+
+    abstract void onCompatShadowChanged();
+
+    final void updatePadding() {
+        Rect rect = mTmpRect;
+        getPadding(rect);
+        onPaddingUpdated(rect);
+        mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom);
+    }
+
+    abstract void getPadding(Rect rect);
+
+    void onPaddingUpdated(Rect padding) {}
+
+    void onAttachedToWindow() {
+        if (requirePreDrawListener()) {
+            ensurePreDrawListener();
+            mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+        }
+    }
+
+    void onDetachedFromWindow() {
+        if (mPreDrawListener != null) {
+            mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
+            mPreDrawListener = null;
+        }
+    }
+
+    boolean requirePreDrawListener() {
+        return false;
+    }
+
+    CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
         final Resources resources = mView.getResources();
         CircularBorderDrawable borderDrawable = newCircularDrawable();
         borderDrawable.setGradientColors(
@@ -71,11 +143,33 @@
                 resources.getColor(R.color.design_fab_stroke_end_inner_color),
                 resources.getColor(R.color.design_fab_stroke_end_outer_color));
         borderDrawable.setBorderWidth(borderWidth);
-        borderDrawable.setTintColor(backgroundTint.getDefaultColor());
+        borderDrawable.setBorderTint(backgroundTint);
         return borderDrawable;
     }
 
     CircularBorderDrawable newCircularDrawable() {
         return new CircularBorderDrawable();
     }
+
+    void onPreDraw() {
+    }
+
+    private void ensurePreDrawListener() {
+        if (mPreDrawListener == null) {
+            mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    FloatingActionButtonImpl.this.onPreDraw();
+                    return true;
+                }
+            };
+        }
+    }
+
+    GradientDrawable createShapeDrawable() {
+        GradientDrawable d = new GradientDrawable();
+        d.setShape(GradientDrawable.OVAL);
+        d.setColor(Color.WHITE);
+        return d;
+    }
 }
diff --git a/design/base/android/support/design/widget/ShadowDrawableWrapper.java b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
index dec1b62..bd7997f 100644
--- a/design/base/android/support/design/widget/ShadowDrawableWrapper.java
+++ b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
@@ -71,6 +71,8 @@
 
     private boolean mAddPaddingForCorners = true;
 
+    private float mRotation;
+
     /**
      * If shadow size is set to a value above max shadow, we print a warning
      */
@@ -195,7 +197,17 @@
         super.draw(canvas);
     }
 
+    final void setRotation(float rotation) {
+        if (mRotation != rotation) {
+            mRotation = rotation;
+            invalidateSelf();
+        }
+    }
+
     private void drawShadow(Canvas canvas) {
+        final int rotateSaved = canvas.save();
+        canvas.rotate(mRotation, mContentBounds.centerX(), mContentBounds.centerY());
+
         final float edgeShadowTop = -mCornerRadius - mShadowSize;
         final float shadowOffset = mCornerRadius;
         final boolean drawHorizontalEdges = mContentBounds.width() - 2 * shadowOffset > 0;
@@ -262,6 +274,8 @@
                     mContentBounds.height() - 2 * shadowOffset, -mCornerRadius, mEdgeShadowPaint);
         }
         canvas.restoreToCount(saved);
+
+        canvas.restoreToCount(rotateSaved);
     }
 
     private void buildShadowCorners() {
diff --git a/design/base/android/support/design/widget/ShadowViewDelegate.java b/design/base/android/support/design/widget/ShadowViewDelegate.java
index 9a395e6..83a3a7a 100644
--- a/design/base/android/support/design/widget/ShadowViewDelegate.java
+++ b/design/base/android/support/design/widget/ShadowViewDelegate.java
@@ -22,4 +22,5 @@
     float getRadius();
     void setShadowPadding(int left, int top, int right, int bottom);
     void setBackgroundDrawable(Drawable background);
+    boolean isCompatPaddingEnabled();
 }
diff --git a/design/base/android/support/design/widget/StateListAnimator.java b/design/base/android/support/design/widget/StateListAnimator.java
index c937b0b..2de5dba 100644
--- a/design/base/android/support/design/widget/StateListAnimator.java
+++ b/design/base/android/support/design/widget/StateListAnimator.java
@@ -124,8 +124,11 @@
         if (mLastMatch != null) {
             cancel();
         }
+
         mLastMatch = match;
-        if (match != null) {
+
+        View view = mViewRef.get();
+        if (match != null && view != null && view.getVisibility() == View.VISIBLE ) {
             start(match);
         }
     }
diff --git a/design/base/android/support/design/widget/ValueAnimatorCompat.java b/design/base/android/support/design/widget/ValueAnimatorCompat.java
index 1e33f66..20bebb6 100644
--- a/design/base/android/support/design/widget/ValueAnimatorCompat.java
+++ b/design/base/android/support/design/widget/ValueAnimatorCompat.java
@@ -104,6 +104,7 @@
         abstract void cancel();
         abstract float getAnimatedFraction();
         abstract void end();
+        abstract long getDuration();
     }
 
     private final Impl mImpl;
@@ -191,4 +192,8 @@
     public void end() {
         mImpl.end();
     }
+
+    public long getDuration() {
+        return mImpl.getDuration();
+    }
 }
diff --git a/design/base/android/support/design/widget/VisibilityAwareImageButton.java b/design/base/android/support/design/widget/VisibilityAwareImageButton.java
new file mode 100644
index 0000000..d7a0b13
--- /dev/null
+++ b/design/base/android/support/design/widget/VisibilityAwareImageButton.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+
+class VisibilityAwareImageButton extends ImageButton {
+
+    private int mUserSetVisibility;
+
+    public VisibilityAwareImageButton(Context context) {
+        this(context, null);
+    }
+
+    public VisibilityAwareImageButton(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public VisibilityAwareImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mUserSetVisibility = getVisibility();
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        internalSetVisibility(visibility, true);
+    }
+
+    final void internalSetVisibility(int visibility, boolean fromUser) {
+        super.setVisibility(visibility);
+        if (fromUser) {
+            mUserSetVisibility = visibility;
+        }
+    }
+
+    final int getUserSetVisibility() {
+        return mUserSetVisibility;
+    }
+}
diff --git a/design/build.gradle b/design/build.gradle
index 5f5482f..401ec8e 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -5,6 +5,7 @@
 dependencies {
     compile project(':support-v4')
     compile project(':support-appcompat-v7')
+    compile project(':support-recyclerview-v7')
 }
 
 android {
@@ -12,7 +13,7 @@
 
     sourceSets {
         main.manifest.srcFile 'AndroidManifest.xml'
-        main.java.srcDirs = ['base', 'eclair-mr1', 'honeycomb', 'honeycomb-mr1', 'lollipop', 'src']
+        main.java.srcDirs = ['base', 'eclair-mr1', 'honeycomb', 'honeycomb-mr1', 'ics', 'lollipop', 'src']
         main.res.srcDirs 'res', 'res-public'
         main.assets.srcDir 'assets'
         main.resources.srcDir 'src'
@@ -38,3 +39,70 @@
         consumerProguardFiles 'proguard-rules.pro'
     }
 }
+
+android.libraryVariants.all { variant ->
+    def name = variant.buildType.name
+
+    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
+        return; // Skip debug builds.
+    }
+    def suffix = name.capitalize()
+
+    def jarTask = project.tasks.create(name: "jar${suffix}", type: Jar){
+        dependsOn variant.javaCompile
+        from variant.javaCompile.destinationDir
+        from 'LICENSE.txt'
+    }
+    def javadocTask = project.tasks.create(name: "javadoc${suffix}", type: Javadoc) {
+        source android.sourceSets.main.java
+        classpath = files(variant.javaCompile.classpath.files) + files(
+                "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
+    }
+
+    def javadocJarTask = project.tasks.create(name: "javadocJar${suffix}", type: Jar) {
+        classifier = 'javadoc'
+        from 'build/docs/javadoc'
+    }
+
+    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
+        classifier = 'sources'
+        from android.sourceSets.main.java.srcDirs
+    }
+
+    artifacts.add('archives', javadocJarTask);
+    artifacts.add('archives', sourcesJarTask);
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri(rootProject.ext.supportRepoOut)) {
+            }
+
+            pom.project {
+                name 'Android Design Support Library'
+                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
+                url 'http://developer.android.com/tools/extras/support-library.html'
+                inceptionYear '2011'
+
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                        distribution 'repo'
+                    }
+                }
+
+                scm {
+                    url "http://source.android.com"
+                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+                }
+                developers {
+                    developer {
+                        name 'The Android Open Source Project'
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java b/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
index 6fb3126..92f9603 100644
--- a/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
+++ b/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
@@ -23,7 +23,9 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.LayerDrawable;
+import android.support.annotation.Nullable;
 import android.support.design.R;
+import android.support.design.widget.AnimationUtils.AnimationListenerAdapter;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.view.View;
 import android.view.animation.Animation;
@@ -31,21 +33,14 @@
 
 class FloatingActionButtonEclairMr1 extends FloatingActionButtonImpl {
 
-    private Drawable mShapeDrawable;
-    private Drawable mRippleDrawable;
-    private Drawable mBorderDrawable;
-
-    private float mElevation;
-    private float mPressedTranslationZ;
     private int mAnimationDuration;
-
     private StateListAnimator mStateListAnimator;
+    private boolean mIsHiding;
 
     ShadowDrawableWrapper mShadowDrawable;
 
-    private boolean mIsHiding;
-
-    FloatingActionButtonEclairMr1(View view, ShadowViewDelegate shadowViewDelegate) {
+    FloatingActionButtonEclairMr1(VisibilityAwareImageButton view,
+            ShadowViewDelegate shadowViewDelegate) {
         super(view, shadowViewDelegate);
 
         mAnimationDuration = view.getResources().getInteger(android.R.integer.config_shortAnimTime);
@@ -64,23 +59,18 @@
     }
 
     @Override
-    void setBackgroundDrawable(Drawable originalBackground, ColorStateList backgroundTint,
+    void setBackgroundDrawable(ColorStateList backgroundTint,
             PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
         // Now we need to tint the original background with the tint, using
         // an InsetDrawable if we have a border width
-        mShapeDrawable = DrawableCompat.wrap(originalBackground.mutate());
+        mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
         DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
         if (backgroundTintMode != null) {
             DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
         }
 
         // Now we created a mask Drawable which will be used for touch feedback.
-        // As we don't know the actual outline of mShapeDrawable, we'll just guess that it's a
-        // circle
-        GradientDrawable touchFeedbackShape = new GradientDrawable();
-        touchFeedbackShape.setShape(GradientDrawable.OVAL);
-        touchFeedbackShape.setColor(Color.WHITE);
-        touchFeedbackShape.setCornerRadius(mShadowViewDelegate.getRadius());
+        GradientDrawable touchFeedbackShape = createShapeDrawable();
 
         // We'll now wrap that touch feedback mask drawable with a ColorStateList. We do not need
         // to inset for any border here as LayerDrawable will nest the padding for us
@@ -97,24 +87,23 @@
             layers = new Drawable[] {mShapeDrawable, mRippleDrawable};
         }
 
+        mContentBackground = new LayerDrawable(layers);
+
         mShadowDrawable = new ShadowDrawableWrapper(
                 mView.getResources(),
-                new LayerDrawable(layers),
+                mContentBackground,
                 mShadowViewDelegate.getRadius(),
                 mElevation,
                 mElevation + mPressedTranslationZ);
         mShadowDrawable.setAddPaddingForCorners(false);
-
         mShadowViewDelegate.setBackgroundDrawable(mShadowDrawable);
-
-        updatePadding();
     }
 
     @Override
     void setBackgroundTintList(ColorStateList tint) {
         DrawableCompat.setTintList(mShapeDrawable, tint);
         if (mBorderDrawable != null) {
-            DrawableCompat.setTintList(mBorderDrawable, tint);
+            mBorderDrawable.setBorderTint(tint);
         }
     }
 
@@ -129,18 +118,21 @@
     }
 
     @Override
-    void setElevation(float elevation) {
-        if (mElevation != elevation && mShadowDrawable != null) {
+    float getElevation() {
+        return mElevation;
+    }
+
+    @Override
+    void onElevationChanged(float elevation) {
+        if (mShadowDrawable != null) {
             mShadowDrawable.setShadowSize(elevation, elevation + mPressedTranslationZ);
-            mElevation = elevation;
             updatePadding();
         }
     }
 
     @Override
-    void setPressedTranslationZ(float translationZ) {
-        if (mPressedTranslationZ != translationZ && mShadowDrawable != null) {
-            mPressedTranslationZ = translationZ;
+    void onTranslationZChanged(float translationZ) {
+        if (mShadowDrawable != null) {
             mShadowDrawable.setMaxShadowSize(mElevation + translationZ);
             updatePadding();
         }
@@ -157,15 +149,18 @@
     }
 
     @Override
-    void hide() {
+    void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
         if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
             // A hide animation is in progress, or we're already hidden. Skip the call
+            if (listener != null) {
+                listener.onHidden();
+            }
             return;
         }
 
         Animation anim = android.view.animation.AnimationUtils.loadAnimation(
                 mView.getContext(), R.anim.design_fab_out);
-        anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+        anim.setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR);
         anim.setDuration(SHOW_HIDE_ANIM_DURATION);
         anim.setAnimationListener(new AnimationUtils.AnimationListenerAdapter() {
             @Override
@@ -176,31 +171,49 @@
             @Override
             public void onAnimationEnd(Animation animation) {
                 mIsHiding = false;
-                mView.setVisibility(View.GONE);
+                mView.internalSetVisibility(View.GONE, fromUser);
+                if (listener != null) {
+                    listener.onHidden();
+                }
             }
         });
         mView.startAnimation(anim);
     }
 
     @Override
-    void show() {
+    void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
         if (mView.getVisibility() != View.VISIBLE || mIsHiding) {
             // If the view is not visible, or is visible and currently being hidden, run
             // the show animation
             mView.clearAnimation();
-            mView.setVisibility(View.VISIBLE);
+            mView.internalSetVisibility(View.VISIBLE, fromUser);
             Animation anim = android.view.animation.AnimationUtils.loadAnimation(
                     mView.getContext(), R.anim.design_fab_in);
             anim.setDuration(SHOW_HIDE_ANIM_DURATION);
-            anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+            anim.setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
+            anim.setAnimationListener(new AnimationListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animation animation) {
+                    if (listener != null) {
+                        listener.onShown();
+                    }
+                }
+            });
             mView.startAnimation(anim);
+        } else {
+            if (listener != null) {
+                listener.onShown();
+            }
         }
     }
 
-    private void updatePadding() {
-        Rect rect = new Rect();
+    @Override
+    void onCompatShadowChanged() {
+        // Ignore pre-v21
+    }
+
+    void getPadding(Rect rect) {
         mShadowDrawable.getPadding(rect);
-        mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom);
     }
 
     private Animation setupAnimation(Animation animation) {
diff --git a/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java b/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java
index 42cf086..1c708f5 100644
--- a/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java
+++ b/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java
@@ -147,6 +147,11 @@
         }
     }
 
+    @Override
+    public long getDuration() {
+        return mDuration;
+    }
+
     private void update() {
         if (mIsRunning) {
             // Update the animated fraction
diff --git a/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java b/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java
deleted file mode 100644
index 72ae009..0000000
--- a/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-
-class FloatingActionButtonHoneycombMr1 extends FloatingActionButtonEclairMr1 {
-
-    private boolean mIsHiding;
-
-    FloatingActionButtonHoneycombMr1(View view, ShadowViewDelegate shadowViewDelegate) {
-        super(view, shadowViewDelegate);
-    }
-
-    @Override
-    void hide() {
-        if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
-            // A hide animation is in progress, or we're already hidden. Skip the call
-            return;
-        }
-
-        if (!ViewCompat.isLaidOut(mView) || mView.isInEditMode()) {
-            // If the view isn't laid out, or we're in the editor, don't run the animation
-            mView.setVisibility(View.GONE);
-        } else {
-            mView.animate()
-                    .scaleX(0f)
-                    .scaleY(0f)
-                    .alpha(0f)
-                    .setDuration(SHOW_HIDE_ANIM_DURATION)
-                    .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                    .setListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationStart(Animator animation) {
-                            mIsHiding = true;
-                            mView.setVisibility(View.VISIBLE);
-                        }
-
-                        @Override
-                        public void onAnimationCancel(Animator animation) {
-                            mIsHiding = false;
-                        }
-
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mIsHiding = false;
-                            mView.setVisibility(View.GONE);
-                        }
-                    });
-        }
-    }
-
-    @Override
-    void show() {
-        if (mView.getVisibility() != View.VISIBLE) {
-            if (ViewCompat.isLaidOut(mView) && !mView.isInEditMode()) {
-                mView.setAlpha(0f);
-                mView.setScaleY(0f);
-                mView.setScaleX(0f);
-                mView.animate()
-                        .scaleX(1f)
-                        .scaleY(1f)
-                        .alpha(1f)
-                        .setDuration(SHOW_HIDE_ANIM_DURATION)
-                        .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                        .setListener(new AnimatorListenerAdapter() {
-                            @Override
-                            public void onAnimationStart(Animator animation) {
-                                mView.setVisibility(View.VISIBLE);
-                            }
-                        });
-            } else {
-                mView.setVisibility(View.VISIBLE);
-                mView.setAlpha(1f);
-                mView.setScaleY(1f);
-                mView.setScaleX(1f);
-            }
-        }
-    }
-}
diff --git a/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java b/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
index 4f9ea39..5ee272b 100644
--- a/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
+++ b/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
@@ -113,4 +113,9 @@
     public void end() {
         mValueAnimator.end();
     }
+
+    @Override
+    public long getDuration() {
+        return mValueAnimator.getDuration();
+    }
 }
diff --git a/design/ics/android/support/design/widget/FloatingActionButtonIcs.java b/design/ics/android/support/design/widget/FloatingActionButtonIcs.java
new file mode 100644
index 0000000..4c256bc
--- /dev/null
+++ b/design/ics/android/support/design/widget/FloatingActionButtonIcs.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+
+class FloatingActionButtonIcs extends FloatingActionButtonEclairMr1 {
+
+    private boolean mIsHiding;
+
+    FloatingActionButtonIcs(VisibilityAwareImageButton view,
+            ShadowViewDelegate shadowViewDelegate) {
+        super(view, shadowViewDelegate);
+    }
+
+    @Override
+    boolean requirePreDrawListener() {
+        return true;
+    }
+
+    @Override
+    void onPreDraw() {
+        updateFromViewRotation(mView.getRotation());
+    }
+
+    @Override
+    void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
+        if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
+            // A hide animation is in progress, or we're already hidden. Skip the call
+            if (listener != null) {
+                listener.onHidden();
+            }
+            return;
+        }
+
+        if (!ViewCompat.isLaidOut(mView) || mView.isInEditMode()) {
+            // If the view isn't laid out, or we're in the editor, don't run the animation
+            mView.internalSetVisibility(View.GONE, fromUser);
+            if (listener != null) {
+                listener.onHidden();
+            }
+        } else {
+            mView.animate().cancel();
+            mView.animate()
+                    .scaleX(0f)
+                    .scaleY(0f)
+                    .alpha(0f)
+                    .setDuration(SHOW_HIDE_ANIM_DURATION)
+                    .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
+                    .setListener(new AnimatorListenerAdapter() {
+                        private boolean mCancelled;
+
+                        @Override
+                        public void onAnimationStart(Animator animation) {
+                            mIsHiding = true;
+                            mCancelled = false;
+                            mView.internalSetVisibility(View.VISIBLE, fromUser);
+                        }
+
+                        @Override
+                        public void onAnimationCancel(Animator animation) {
+                            mIsHiding = false;
+                            mCancelled = true;
+                        }
+
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mIsHiding = false;
+                            if (!mCancelled) {
+                                mView.internalSetVisibility(View.GONE, fromUser);
+                                if (listener != null) {
+                                    listener.onHidden();
+                                }
+                            }
+                        }
+                    });
+        }
+    }
+
+    @Override
+    void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
+        if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
+            if (ViewCompat.isLaidOut(mView) && !mView.isInEditMode()) {
+                mView.animate().cancel();
+                if (mView.getVisibility() != View.VISIBLE) {
+                    // If the view isn't visible currently, we'll animate it from a single pixel
+                    mView.setAlpha(0f);
+                    mView.setScaleY(0f);
+                    mView.setScaleX(0f);
+                }
+                mView.animate()
+                        .scaleX(1f)
+                        .scaleY(1f)
+                        .alpha(1f)
+                        .setDuration(SHOW_HIDE_ANIM_DURATION)
+                        .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
+                        .setListener(new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationStart(Animator animation) {
+                                mView.internalSetVisibility(View.VISIBLE, fromUser);
+                            }
+
+                            @Override
+                            public void onAnimationEnd(Animator animation) {
+                                if (listener != null) {
+                                    listener.onShown();
+                                }
+                            }
+                        });
+            } else {
+                mView.internalSetVisibility(View.VISIBLE, fromUser);
+                mView.setAlpha(1f);
+                mView.setScaleY(1f);
+                mView.setScaleX(1f);
+                if (listener != null) {
+                    listener.onShown();
+                }
+            }
+        }
+    }
+
+    private void updateFromViewRotation(float rotation) {
+        // Offset any View rotation
+        if (mShadowDrawable != null) {
+            mShadowDrawable.setRotation(-rotation);
+        }
+        if (mBorderDrawable != null) {
+            mBorderDrawable.setRotation(-rotation);
+        }
+    }
+}
diff --git a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java b/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
index 554ecb8..8b90361 100644
--- a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
+++ b/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
@@ -16,70 +16,17 @@
 
 package android.support.design.widget;
 
-
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Outline;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 
 /**
- * Lollipop version of {@link CircularBorderDrawable} which accepts tint calls.
+ * Lollipop version of {@link CircularBorderDrawable}.
  */
 class CircularBorderDrawableLollipop extends CircularBorderDrawable {
 
-    private ColorStateList mTint;
-    private PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_IN;
-    private PorterDuffColorFilter mTintFilter;
-
-    @Override
-    public void draw(Canvas canvas) {
-        boolean clearColorFilter;
-        if (mTintFilter != null && mPaint.getColorFilter() == null) {
-            mPaint.setColorFilter(mTintFilter);
-            clearColorFilter = true;
-        } else {
-            clearColorFilter = false;
-        }
-
-        super.draw(canvas);
-
-        if (clearColorFilter) {
-            mPaint.setColorFilter(null);
-        }
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mTint = tint;
-        mTintFilter = updateTintFilter(tint, mTintMode);
-        invalidateSelf();
-    }
-
-    @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
-        mTintMode = tintMode;
-        mTintFilter = updateTintFilter(mTint, tintMode);
-        invalidateSelf();
-    }
-
     @Override
     public void getOutline(Outline outline) {
         copyBounds(mRect);
         outline.setOval(mRect);
     }
 
-    /**
-     * Ensures the tint filter is consistent with the current tint color and
-     * mode.
-     */
-    private PorterDuffColorFilter updateTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) {
-        if (tint == null || tintMode == null) {
-            return null;
-        }
-
-        final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
-        return new PorterDuffColorFilter(color, tintMode);
-    }
 }
diff --git a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
index eb4360b..2b85845 100644
--- a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
+++ b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
@@ -22,39 +22,37 @@
 import android.annotation.TargetApi;
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.os.Build;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.view.ViewCompat;
-import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-class FloatingActionButtonLollipop extends FloatingActionButtonHoneycombMr1 {
+class FloatingActionButtonLollipop extends FloatingActionButtonIcs {
 
-    private Drawable mShapeDrawable;
-    private RippleDrawable mRippleDrawable;
-    private Drawable mBorderDrawable;
+    private final Interpolator mInterpolator;
+    private InsetDrawable mInsetDrawable;
 
-    private Interpolator mInterpolator;
-
-    FloatingActionButtonLollipop(View view, ShadowViewDelegate shadowViewDelegate) {
+    FloatingActionButtonLollipop(VisibilityAwareImageButton view,
+            ShadowViewDelegate shadowViewDelegate) {
         super(view, shadowViewDelegate);
 
-        if (!view.isInEditMode()) {
-            mInterpolator = AnimationUtils.loadInterpolator(mView.getContext(),
-                    android.R.interpolator.fast_out_slow_in);
-        }
+        mInterpolator = view.isInEditMode() ? null
+                : AnimationUtils.loadInterpolator(mView.getContext(),
+                        android.R.interpolator.fast_out_slow_in);
     }
 
     @Override
-    void setBackgroundDrawable(Drawable originalBackground, ColorStateList backgroundTint,
+    void setBackgroundDrawable(ColorStateList backgroundTint,
             PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
-        // Now we need to tint the original background with the tint
-        mShapeDrawable = DrawableCompat.wrap(originalBackground.mutate());
+        // Now we need to tint the shape background with the tint
+        mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
         DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
         if (backgroundTintMode != null) {
             DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
@@ -72,37 +70,31 @@
         mRippleDrawable = new RippleDrawable(ColorStateList.valueOf(rippleColor),
                 rippleContent, null);
 
+        mContentBackground = mRippleDrawable;
+
         mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable);
-        mShadowViewDelegate.setShadowPadding(0, 0, 0, 0);
-    }
-
-    @Override
-    void setBackgroundTintList(ColorStateList tint) {
-        DrawableCompat.setTintList(mShapeDrawable, tint);
-        if (mBorderDrawable != null) {
-            DrawableCompat.setTintList(mBorderDrawable, tint);
-        }
-    }
-
-    @Override
-    void setBackgroundTintMode(PorterDuff.Mode tintMode) {
-        DrawableCompat.setTintMode(mShapeDrawable, tintMode);
     }
 
     @Override
     void setRippleColor(int rippleColor) {
-        mRippleDrawable.setColor(ColorStateList.valueOf(rippleColor));
+        if (mRippleDrawable instanceof RippleDrawable) {
+            ((RippleDrawable) mRippleDrawable).setColor(ColorStateList.valueOf(rippleColor));
+        } else {
+            super.setRippleColor(rippleColor);
+        }
     }
 
     @Override
-    public void setElevation(float elevation) {
-        ViewCompat.setElevation(mView, elevation);
+    public void onElevationChanged(float elevation) {
+        mView.setElevation(elevation);
+        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+            updatePadding();
+        }
     }
 
     @Override
-    void setPressedTranslationZ(float translationZ) {
+    void onTranslationZChanged(float translationZ) {
         StateListAnimator stateListAnimator = new StateListAnimator();
-
         // Animate translationZ to our value when pressed or focused
         stateListAnimator.addState(PRESSED_ENABLED_STATE_SET,
                 setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", translationZ)));
@@ -111,8 +103,32 @@
         // Animate translationZ to 0 otherwise
         stateListAnimator.addState(EMPTY_STATE_SET,
                 setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", 0f)));
-
         mView.setStateListAnimator(stateListAnimator);
+
+        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+            updatePadding();
+        }
+    }
+
+    @Override
+    public float getElevation() {
+        return mView.getElevation();
+    }
+
+    @Override
+    void onCompatShadowChanged() {
+        updatePadding();
+    }
+
+    @Override
+    void onPaddingUpdated(Rect padding) {
+        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+            mInsetDrawable = new InsetDrawable(mRippleDrawable,
+                    padding.left, padding.top, padding.right, padding.bottom);
+            mShadowViewDelegate.setBackgroundDrawable(mInsetDrawable);
+        } else {
+            mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable);
+        }
     }
 
     @Override
@@ -125,6 +141,11 @@
         // no-op
     }
 
+    @Override
+    boolean requirePreDrawListener() {
+        return false;
+    }
+
     private Animator setupAnimator(Animator animator) {
         animator.setInterpolator(mInterpolator);
         return animator;
@@ -134,4 +155,18 @@
     CircularBorderDrawable newCircularDrawable() {
         return new CircularBorderDrawableLollipop();
     }
+
+    void getPadding(Rect rect) {
+        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+            final float radius = mShadowViewDelegate.getRadius();
+            final float maxShadowSize = getElevation() + mPressedTranslationZ;
+            final int hPadding = (int) Math.ceil(
+                    ShadowDrawableWrapper.calculateHorizontalPadding(maxShadowSize, radius, false));
+            final int vPadding = (int) Math.ceil(
+                    ShadowDrawableWrapper.calculateVerticalPadding(maxShadowSize, radius, false));
+            rect.set(hPadding, vPadding, hPadding, vPadding);
+        } else {
+            rect.set(0, 0, 0, 0);
+        }
+    }
 }
diff --git a/design/proguard-rules.pro b/design/proguard-rules.pro
index ea77945..96e2ee0 100644
--- a/design/proguard-rules.pro
+++ b/design/proguard-rules.pro
@@ -17,3 +17,6 @@
     public <init>(android.content.Context, android.util.AttributeSet);
     public <init>();
 }
+
+# Make sure we keep annotations for CoordinatorLayout's DefaultBehavior
+-keepattributes *Annotation*
diff --git a/design/res-public/values/public_attrs.xml b/design/res-public/values/public_attrs.xml
index 30aa70a..8c8eb0d 100644
--- a/design/res-public/values/public_attrs.xml
+++ b/design/res-public/values/public_attrs.xml
@@ -25,6 +25,10 @@
     <public type="attr" name="elevation"/>
     <public type="attr" name="errorEnabled"/>
     <public type="attr" name="errorTextAppearance"/>
+    <public type="attr" name="counterEnabled"/>
+    <public type="attr" name="counterMaxLength"/>
+    <public type="attr" name="counterTextAppearance"/>
+    <public type="attr" name="counterOverflowTextAppearance"/>
     <public type="attr" name="expanded"/>
     <public type="attr" name="expandedTitleGravity"/>
     <public type="attr" name="expandedTitleMargin"/>
@@ -66,4 +70,5 @@
     <public type="attr" name="title"/>
     <public type="attr" name="titleEnabled"/>
     <public type="attr" name="toolbarId"/>
+    <public type="attr" name="behavior_peekHeight"/>
 </resources>
diff --git a/design/res/layout/design_layout_tab_icon.xml b/design/res/layout/design_layout_tab_icon.xml
index 6464d1f..5dcfa11 100644
--- a/design/res/layout/design_layout_tab_icon.xml
+++ b/design/res/layout/design_layout_tab_icon.xml
@@ -16,6 +16,6 @@
   -->
 
 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
-           android:layout_width="wrap_content"
-           android:layout_height="wrap_content"
-           android:layout_gravity="center"/>
\ No newline at end of file
+           android:layout_width="24dp"
+           android:layout_height="24dp"
+           android:scaleType="centerInside"/>
\ No newline at end of file
diff --git a/v17/preference-leanback/res/values/ids.xml b/design/res/layout/design_menu_item_action_area.xml
similarity index 74%
copy from v17/preference-leanback/res/values/ids.xml
copy to design/res/layout/design_menu_item_action_area.xml
index 20c1eda..ba8141d 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/design/res/layout/design_menu_item_action_area.xml
@@ -12,9 +12,8 @@
   ~ 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>
-    <item name="transitionPosition" type="id" />
-</resources>
+  ~ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="wrap_content"
+             android:layout_height="match_parent"/>
diff --git a/design/res/layout/design_navigation_item.xml b/design/res/layout/design_navigation_item.xml
index 3fcd74a..ccd42de 100644
--- a/design/res/layout/design_navigation_item.xml
+++ b/design/res/layout/design_navigation_item.xml
@@ -20,7 +20,5 @@
         android:layout_height="?attr/listPreferredItemHeightSmall"
         android:paddingLeft="?attr/listPreferredItemPaddingLeft"
         android:paddingRight="?attr/listPreferredItemPaddingRight"
-        android:drawablePadding="@dimen/design_navigation_icon_padding"
-        android:gravity="center_vertical|start"
-        android:maxLines="1"
-        android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
+        android:foreground="?attr/selectableItemBackground"
+        android:focusable="true"/>
diff --git a/design/res/layout/design_navigation_item_header.xml b/design/res/layout/design_navigation_item_header.xml
index 33fd199..8d03f69 100644
--- a/design/res/layout/design_navigation_item_header.xml
+++ b/design/res/layout/design_navigation_item_header.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+      android:id="@+id/navigation_header_container"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical"
diff --git a/design/res/layout/design_navigation_menu.xml b/design/res/layout/design_navigation_menu.xml
index 02b7aad..4d85081 100644
--- a/design/res/layout/design_navigation_menu.xml
+++ b/design/res/layout/design_navigation_menu.xml
@@ -16,11 +16,10 @@
 -->
 <android.support.design.internal.NavigationMenuView
         xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/design_navigation_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:paddingTop="@dimen/design_navigation_padding_top_default"
         android:paddingBottom="@dimen/design_navigation_padding_bottom"
         android:clipToPadding="false"
-        android:divider="@null"
-        android:scrollbars="vertical"
-        android:listSelector="?attr/selectableItemBackground"/>
+        android:scrollbars="vertical"/>
diff --git a/design/res/layout/design_navigation_menu_item.xml b/design/res/layout/design_navigation_menu_item.xml
new file mode 100644
index 0000000..91104bb1
--- /dev/null
+++ b/design/res/layout/design_navigation_menu_item.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <CheckedTextView
+            android:id="@+id/design_menu_item_text"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:drawablePadding="@dimen/design_navigation_icon_padding"
+            android:gravity="center_vertical|start"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
+
+    <ViewStub
+            android:id="@+id/design_menu_item_action_area_stub"
+            android:inflatedId="@+id/design_menu_item_action_area"
+            android:layout="@layout/design_menu_item_action_area"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"/>
+
+</merge>
diff --git a/design/res/values-sw600dp/dimens.xml b/design/res/values-sw600dp/dimens.xml
index ebbc20e..8dada20 100644
--- a/design/res/values-sw600dp/dimens.xml
+++ b/design/res/values-sw600dp/dimens.xml
@@ -17,7 +17,7 @@
 
 <resources>
 
-    <dimen name="design_tab_min_width">160dp</dimen>
+    <dimen name="design_tab_scrollable_min_width">160dp</dimen>
 
     <dimen name="design_snackbar_min_width">320dp</dimen>
     <dimen name="design_snackbar_max_width">576dp</dimen>
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 785308a..29ca0af 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -18,7 +18,6 @@
 
     <declare-styleable name="FloatingActionButton">
         <!-- Background for the FloatingActionButton -->
-        <attr name="android:background"/>
         <attr name="backgroundTint"/>
         <attr name="backgroundTintMode"/>
 
@@ -35,6 +34,8 @@
         <attr name="pressedTranslationZ" format="dimension"/>
         <!-- The width of the border around the FAB. -->
         <attr name="borderWidth" format="dimension"/>
+        <!-- Enable compat padding. -->
+        <attr name="useCompatPadding" format="boolean"/>
     </declare-styleable>
 
     <declare-styleable name="ScrimInsetsFrameLayout">
@@ -56,6 +57,12 @@
         <attr name="headerLayout" format="reference"/>
     </declare-styleable>
 
+    <declare-styleable name="ForegroundLinearLayout">
+        <attr name="android:foreground" />
+        <attr name="android:foregroundGravity" />
+        <attr name="foregroundInsidePadding" format="boolean" />
+    </declare-styleable>
+
     <declare-styleable name="TabLayout">
         <attr name="tabIndicatorColor" format="color"/>
         <attr name="tabIndicatorHeight" format="dimension"/>
@@ -157,10 +164,20 @@
         <attr name="hintTextAppearance" format="reference"/>
         <!-- The hint to display in the floating label -->
         <attr name="android:hint"/>
+        <!-- Whether the layout's floating label functionality is enabled -->
+        <attr name="hintEnabled" format="boolean"/>
         <!-- Whether the layout is laid out as if an error will be displayed -->
         <attr name="errorEnabled" format="boolean"/>
         <!-- TextAppearance of any error message displayed -->
         <attr name="errorTextAppearance" format="reference"/>
+        <!-- Whether the layout is laid out as if the character counter will be displayed -->
+        <attr name="counterEnabled" format="boolean"/>
+        <!-- The max length to display in the character counter -->
+        <attr name="counterMaxLength" format="integer" />
+        <!-- TextAppearance of the character counter -->
+        <attr name="counterTextAppearance" format="reference"/>
+        <!-- TextAppearance of the character counter when the text is longer than the max -->
+        <attr name="counterOverflowTextAppearance" format="reference"/>
         <attr name="android:textColorHint"/>
         <!-- Whether to animate hint state changes. -->
         <attr name="hintAnimationEnabled" format="boolean"/>
@@ -201,6 +218,10 @@
                  reached the end of it's scroll range, the remainder of this view will be scrolled
                  into view. -->
             <flag name="enterAlwaysCollapsed" value="0x8"/>
+
+            <!-- Upon a scroll ending, if the view is only partially visible then it will be
+                 snapped and scrolled to it's closest edge. -->
+            <flag name="snap" value="0x10"/>
         </attr>
 
         <!-- An interpolator to use when scrolling this View. Only takes effect when View
@@ -316,5 +337,10 @@
         <attr name="layout_collapseParallaxMultiplier" format="float"/>
     </declare-styleable>
 
+    <declare-styleable name="BottomSheetBehavior_Params">
+        <!-- The height of the bottom sheet when it is collapsed. -->
+        <attr name="behavior_peekHeight" format="dimension"/>
+    </declare-styleable>
+
 </resources>
 
diff --git a/design/res/values/dimens.xml b/design/res/values/dimens.xml
index c7f8cef..a0a536d 100644
--- a/design/res/values/dimens.xml
+++ b/design/res/values/dimens.xml
@@ -18,7 +18,7 @@
 
     <dimen name="design_fab_elevation">6dp</dimen>
     <dimen name="design_fab_translation_z_pressed">6dp</dimen>
-    <dimen name="design_fab_content_size">24dp</dimen>
+    <dimen name="design_fab_image_size">24dp</dimen>
     <dimen name="design_fab_size_normal">56dp</dimen>
     <dimen name="design_fab_size_mini">40dp</dimen>
     <dimen name="design_fab_border_width">0.5dp</dimen>
@@ -31,8 +31,10 @@
     <dimen name="design_navigation_padding_top_default">0dp</dimen>
     <dimen name="design_navigation_padding_bottom">8dp</dimen>
 
-    <dimen name="design_tab_min_width">72dp</dimen>
+    <dimen name="design_tab_scrollable_min_width">72dp</dimen>
     <dimen name="design_tab_max_width">264dp</dimen>
+    <dimen name="design_tab_text_size">14sp</dimen>
+    <dimen name="design_tab_text_size_2line">12sp</dimen>
 
     <dimen name="design_snackbar_min_width">-1px</dimen>
     <dimen name="design_snackbar_max_width">-1px</dimen>
diff --git a/design/res/values/strings.xml b/design/res/values/strings.xml
index 4c02de1..416d289 100644
--- a/design/res/values/strings.xml
+++ b/design/res/values/strings.xml
@@ -17,5 +17,7 @@
 <resources>
     <!-- The class name to the ScrollingChildBehavior required for AppBarLayout -->
     <string name="appbar_scrolling_view_behavior" translatable="false">android.support.design.widget.AppBarLayout$ScrollingViewBehavior</string>
+    <!-- The text pattern for the character counter -->
+    <string name="character_counter_pattern" translatable="false">%1$d / %2$d</string>
 </resources>
 
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
index e75d805..24a9aa9 100644
--- a/design/res/values/styles.xml
+++ b/design/res/values/styles.xml
@@ -54,7 +54,7 @@
     </style>
 
     <style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">@dimen/design_tab_text_size</item>
         <item name="android:textColor">?android:textColorSecondary</item>
         <item name="textAllCaps">true</item>
     </style>
@@ -62,6 +62,8 @@
     <style name="Widget.Design.TextInputLayout" parent="android:Widget">
         <item name="hintTextAppearance">@style/TextAppearance.Design.Hint</item>
         <item name="errorTextAppearance">@style/TextAppearance.Design.Error</item>
+        <item name="counterTextAppearance">@style/TextAppearance.Design.Counter</item>
+        <item name="counterOverflowTextAppearance">@style/TextAppearance.Design.Counter.Overflow</item>
     </style>
 
     <style name="TextAppearance.Design.Hint" parent="TextAppearance.AppCompat.Caption">
@@ -72,6 +74,12 @@
         <item name="android:textColor">@color/design_textinput_error_color</item>
     </style>
 
+    <style name="TextAppearance.Design.Counter" parent="TextAppearance.AppCompat.Caption"/>
+
+    <style name="TextAppearance.Design.Counter.Overflow" parent="TextAppearance.AppCompat.Caption">
+        <item name="android:textColor">@color/design_textinput_error_color</item>
+    </style>
+
     <style name="TextAppearance.Design.Snackbar.Message" parent="android:TextAppearance">
         <item name="android:textSize">@dimen/design_snackbar_text_size</item>
         <item name="android:textColor">?android:textColorPrimary</item>
diff --git a/design/src/android/support/design/internal/ForegroundLinearLayout.java b/design/src/android/support/design/internal/ForegroundLinearLayout.java
new file mode 100644
index 0000000..eff89e3
--- /dev/null
+++ b/design/src/android/support/design/internal/ForegroundLinearLayout.java
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+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.design.R;
+import android.support.v7.widget.LinearLayoutCompat;
+import android.util.AttributeSet;
+import android.view.Gravity;
+
+/**
+ * @hide
+ */
+public class ForegroundLinearLayout extends LinearLayoutCompat {
+
+    private Drawable mForeground;
+
+    private final Rect mSelfBounds = new Rect();
+
+    private final Rect mOverlayBounds = new Rect();
+
+    private int mForegroundGravity = Gravity.FILL;
+
+    protected boolean mForegroundInPadding = true;
+
+    boolean mForegroundBoundsChanged = false;
+
+    public ForegroundLinearLayout(Context context) {
+        this(context, null);
+    }
+
+    public ForegroundLinearLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ForegroundLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundLinearLayout,
+                defStyle, 0);
+
+        mForegroundGravity = a.getInt(
+                R.styleable.ForegroundLinearLayout_android_foregroundGravity, mForegroundGravity);
+
+        final Drawable d = a.getDrawable(R.styleable.ForegroundLinearLayout_android_foreground);
+        if (d != null) {
+            setForeground(d);
+        }
+
+        mForegroundInPadding = a.getBoolean(
+                R.styleable.ForegroundLinearLayout_foregroundInsidePadding, true);
+
+        a.recycle();
+    }
+
+    /**
+     * Describes how the foreground is positioned.
+     *
+     * @return foreground gravity.
+     * @see #setForegroundGravity(int)
+     */
+    public int getForegroundGravity() {
+        return mForegroundGravity;
+    }
+
+    /**
+     * Describes how the foreground is positioned. Defaults to START and TOP.
+     *
+     * @param foregroundGravity See {@link android.view.Gravity}
+     * @see #getForegroundGravity()
+     */
+    public void setForegroundGravity(int foregroundGravity) {
+        if (mForegroundGravity != foregroundGravity) {
+            if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
+                foregroundGravity |= Gravity.START;
+            }
+
+            if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
+                foregroundGravity |= Gravity.TOP;
+            }
+
+            mForegroundGravity = foregroundGravity;
+
+            if (mForegroundGravity == Gravity.FILL && mForeground != null) {
+                Rect padding = new Rect();
+                mForeground.getPadding(padding);
+            }
+
+            requestLayout();
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || (who == mForeground);
+    }
+
+    @Override
+    public void jumpDrawablesToCurrentState() {
+        super.jumpDrawablesToCurrentState();
+        if (mForeground != null) {
+            mForeground.jumpToCurrentState();
+        }
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mForeground != null && mForeground.isStateful()) {
+            mForeground.setState(getDrawableState());
+        }
+    }
+
+    /**
+     * Supply a Drawable that is to be rendered on top of all of the child
+     * views in the frame layout.  Any padding in the Drawable will be taken
+     * into account by ensuring that the children are inset to be placed
+     * inside of the padding area.
+     *
+     * @param drawable The Drawable to be drawn on top of the children.
+     */
+    public void setForeground(Drawable drawable) {
+        if (mForeground != drawable) {
+            if (mForeground != null) {
+                mForeground.setCallback(null);
+                unscheduleDrawable(mForeground);
+            }
+
+            mForeground = drawable;
+
+            if (drawable != null) {
+                setWillNotDraw(false);
+                drawable.setCallback(this);
+                if (drawable.isStateful()) {
+                    drawable.setState(getDrawableState());
+                }
+                if (mForegroundGravity == Gravity.FILL) {
+                    Rect padding = new Rect();
+                    drawable.getPadding(padding);
+                }
+            } else {
+                setWillNotDraw(true);
+            }
+            requestLayout();
+            invalidate();
+        }
+    }
+
+    /**
+     * Returns the drawable used as the foreground of this FrameLayout. The
+     * foreground drawable, if non-null, is always drawn on top of the children.
+     *
+     * @return A Drawable or null if no foreground was set.
+     */
+    public Drawable getForeground() {
+        return mForeground;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        mForegroundBoundsChanged |= changed;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mForegroundBoundsChanged = true;
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        super.draw(canvas);
+
+        if (mForeground != null) {
+            final Drawable foreground = mForeground;
+
+            if (mForegroundBoundsChanged) {
+                mForegroundBoundsChanged = false;
+                final Rect selfBounds = mSelfBounds;
+                final Rect overlayBounds = mOverlayBounds;
+
+                final int w = getRight() - getLeft();
+                final int h = getBottom() - getTop();
+
+                if (mForegroundInPadding) {
+                    selfBounds.set(0, 0, w, h);
+                } else {
+                    selfBounds.set(getPaddingLeft(), getPaddingTop(),
+                            w - getPaddingRight(), h - getPaddingBottom());
+                }
+
+                Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
+                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
+                foreground.setBounds(overlayBounds);
+            }
+
+            foreground.draw(canvas);
+        }
+    }
+
+    @Override
+    public void drawableHotspotChanged(float x, float y) {
+        super.drawableHotspotChanged(x, y);
+        if (mForeground != null) {
+            mForeground.setHotspot(x, y);
+        }
+    }
+
+}
diff --git a/design/src/android/support/design/internal/NavigationMenu.java b/design/src/android/support/design/internal/NavigationMenu.java
index 4335631..2821d36 100644
--- a/design/src/android/support/design/internal/NavigationMenu.java
+++ b/design/src/android/support/design/internal/NavigationMenu.java
@@ -17,9 +17,9 @@
 package android.support.design.internal;
 
 import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.SubMenuBuilder;
 import android.view.SubMenu;
 
 /**
diff --git a/design/src/android/support/design/internal/NavigationMenuItemView.java b/design/src/android/support/design/internal/NavigationMenuItemView.java
index 7813163..0423345 100644
--- a/design/src/android/support/design/internal/NavigationMenuItemView.java
+++ b/design/src/android/support/design/internal/NavigationMenuItemView.java
@@ -25,21 +25,31 @@
 import android.support.design.R;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.widget.TextViewCompat;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuView;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuView;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.widget.TextView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewStub;
+import android.widget.CheckedTextView;
+import android.widget.FrameLayout;
 
 /**
  * @hide
  */
-public class NavigationMenuItemView extends TextView implements MenuView.ItemView {
+public class NavigationMenuItemView extends ForegroundLinearLayout implements MenuView.ItemView {
 
     private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
 
-    private int mIconSize;
+    private final int mIconSize;
+
+    private final CheckedTextView mTextView;
+
+    private FrameLayout mActionArea;
+
     private MenuItemImpl mItemData;
+
     private ColorStateList mIconTintList;
 
     public NavigationMenuItemView(Context context) {
@@ -52,8 +62,12 @@
 
     public NavigationMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        setOrientation(HORIZONTAL);
+        LayoutInflater.from(context).inflate(R.layout.design_navigation_menu_item, this, true);
         mIconSize = context.getResources().getDimensionPixelSize(
                 R.dimen.design_navigation_icon_size);
+        mTextView = (CheckedTextView) findViewById(R.id.design_menu_item_text);
+        mTextView.setDuplicateParentStateEnabled(true);
     }
 
     @Override
@@ -71,6 +85,25 @@
         setEnabled(itemData.isEnabled());
         setTitle(itemData.getTitle());
         setIcon(itemData.getIcon());
+        setActionView(itemData.getActionView());
+    }
+
+    public void recycle() {
+        if (mActionArea != null) {
+            mActionArea.removeAllViews();
+        }
+        mTextView.setCompoundDrawables(null, null, null, null);
+    }
+
+    private void setActionView(View actionView) {
+        if (mActionArea == null) {
+            mActionArea = (FrameLayout) ((ViewStub) findViewById(
+                    R.id.design_menu_item_action_area_stub)).inflate();
+        }
+        mActionArea.removeAllViews();
+        if (actionView != null) {
+            mActionArea.addView(actionView);
+        }
     }
 
     private StateListDrawable createDefaultBackground() {
@@ -91,7 +124,7 @@
 
     @Override
     public void setTitle(CharSequence title) {
-        setText(title);
+        mTextView.setText(title);
     }
 
     @Override
@@ -102,6 +135,7 @@
     @Override
     public void setChecked(boolean checked) {
         refreshDrawableState();
+        mTextView.setChecked(checked);
     }
 
     @Override
@@ -111,11 +145,12 @@
     @Override
     public void setIcon(Drawable icon) {
         if (icon != null) {
-            icon = DrawableCompat.wrap(icon.getConstantState().newDrawable()).mutate();
+            Drawable.ConstantState state = icon.getConstantState();
+            icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate();
             icon.setBounds(0, 0, mIconSize, mIconSize);
             DrawableCompat.setTintList(icon, mIconTintList);
         }
-        TextViewCompat.setCompoundDrawablesRelative(this, icon, null, null, null);
+        TextViewCompat.setCompoundDrawablesRelative(mTextView, icon, null, null, null);
     }
 
     @Override
@@ -144,4 +179,13 @@
             setIcon(mItemData.getIcon());
         }
     }
+
+    public void setTextAppearance(Context context, int textAppearance) {
+        mTextView.setTextAppearance(context, textAppearance);
+    }
+
+    public void setTextColor(ColorStateList colors) {
+        mTextView.setTextColor(colors);
+    }
+
 }
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index e523c38..959c0e7 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -28,19 +28,18 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.StyleRes;
 import android.support.design.R;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
+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.support.v7.widget.RecyclerView;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -49,13 +48,13 @@
 /**
  * @hide
  */
-public class NavigationMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
+public class NavigationMenuPresenter implements MenuPresenter {
 
     private static final String STATE_HIERARCHY = "android:menu:list";
     private static final String STATE_ADAPTER = "android:menu:adapter";
 
     private NavigationMenuView mMenuView;
-    private LinearLayout mHeader;
+    private LinearLayout mHeaderLayout;
 
     private Callback mCallback;
     private MenuBuilder mMenu;
@@ -100,11 +99,10 @@
             if (mAdapter == null) {
                 mAdapter = new NavigationMenuAdapter();
             }
-            mHeader = (LinearLayout) mLayoutInflater.inflate(R.layout.design_navigation_item_header,
-                    mMenuView, false);
-            mMenuView.addHeaderView(mHeader, null, false);
+            mHeaderLayout = (LinearLayout) mLayoutInflater
+                    .inflate(R.layout.design_navigation_item_header,
+                            mMenuView, false);
             mMenuView.setAdapter(mAdapter);
-            mMenuView.setOnItemClickListener(this);
         }
         return mMenuView;
     }
@@ -112,7 +110,7 @@
     @Override
     public void updateMenuView(boolean cleared) {
         if (mAdapter != null) {
-            mAdapter.notifyDataSetChanged();
+            mAdapter.update();
         }
     }
 
@@ -184,44 +182,37 @@
         }
     }
 
-    @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        int positionInAdapter = position - mMenuView.getHeaderViewsCount();
-        if (positionInAdapter >= 0) {
-            setUpdateSuspended(true);
-            MenuItemImpl item = mAdapter.getItem(positionInAdapter).getMenuItem();
-            if (item != null && item.isCheckable()) {
-                mAdapter.setCheckedItem(item);
-            }
-            mMenu.performItemAction(item, this, 0);
-            setUpdateSuspended(false);
-            updateMenuView(false);
-        }
-    }
-
     public void setCheckedItem(MenuItemImpl item) {
         mAdapter.setCheckedItem(item);
     }
 
     public View inflateHeaderView(@LayoutRes int res) {
-        View view = mLayoutInflater.inflate(res, mHeader, false);
+        View view = mLayoutInflater.inflate(res, mHeaderLayout, false);
         addHeaderView(view);
         return view;
     }
 
     public void addHeaderView(@NonNull View view) {
-        mHeader.addView(view);
+        mHeaderLayout.addView(view);
         // The padding on top should be cleared.
         mMenuView.setPadding(0, 0, 0, mMenuView.getPaddingBottom());
     }
 
     public void removeHeaderView(@NonNull View view) {
-        mHeader.removeView(view);
-        if (mHeader.getChildCount() == 0) {
+        mHeaderLayout.removeView(view);
+        if (mHeaderLayout.getChildCount() == 0) {
             mMenuView.setPadding(0, mPaddingTopDefault, 0, mMenuView.getPaddingBottom());
         }
     }
 
+    public int getHeaderCount() {
+        return mHeaderLayout.getChildCount();
+    }
+
+    public View getHeaderView(int index) {
+        return mHeaderLayout.getChildAt(index);
+    }
+
     @Nullable
     public ColorStateList getItemTintList() {
         return mIconTintList;
@@ -262,13 +253,77 @@
         }
     }
 
-    private class NavigationMenuAdapter extends BaseAdapter {
+    private abstract static class ViewHolder extends RecyclerView.ViewHolder {
+
+        public ViewHolder(View itemView) {
+            super(itemView);
+        }
+
+    }
+
+    private static class NormalViewHolder extends ViewHolder {
+
+        public NormalViewHolder(LayoutInflater inflater, ViewGroup parent,
+                View.OnClickListener listener) {
+            super(inflater.inflate(R.layout.design_navigation_item, parent, false));
+            itemView.setOnClickListener(listener);
+        }
+
+    }
+
+    private static class SubheaderViewHolder extends ViewHolder {
+
+        public SubheaderViewHolder(LayoutInflater inflater, ViewGroup parent) {
+            super(inflater.inflate(R.layout.design_navigation_item_subheader, parent, false));
+        }
+
+    }
+
+    private static class SeparatorViewHolder extends ViewHolder {
+
+        public SeparatorViewHolder(LayoutInflater inflater, ViewGroup parent) {
+            super(inflater.inflate(R.layout.design_navigation_item_separator, parent, false));
+        }
+
+    }
+
+    private static class HeaderViewHolder extends ViewHolder {
+
+        public HeaderViewHolder(View itemView) {
+            super(itemView);
+        }
+
+    }
+
+    /**
+     * Handles click events for the menu items. The items has to be {@link NavigationMenuItemView}.
+     */
+    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+
+        @Override
+        public void onClick(View v) {
+            NavigationMenuItemView itemView = (NavigationMenuItemView) v;
+            setUpdateSuspended(true);
+            MenuItemImpl item = itemView.getItemData();
+            boolean result = mMenu.performItemAction(item, NavigationMenuPresenter.this, 0);
+            if (item != null && item.isCheckable() && result) {
+                mAdapter.setCheckedItem(item);
+            }
+            setUpdateSuspended(false);
+            updateMenuView(false);
+        }
+
+    };
+
+    private class NavigationMenuAdapter extends RecyclerView.Adapter<ViewHolder> {
 
         private static final String STATE_CHECKED_ITEM = "android:menu:checked";
 
+        private static final String STATE_ACTION_VIEWS = "android:menu:action_views";
         private static final int VIEW_TYPE_NORMAL = 0;
         private static final int VIEW_TYPE_SUBHEADER = 1;
         private static final int VIEW_TYPE_SEPARATOR = 2;
+        private static final int VIEW_TYPE_HEADER = 3;
 
         private final ArrayList<NavigationMenuItem> mItems = new ArrayList<>();
         private MenuItemImpl mCheckedItem;
@@ -280,48 +335,53 @@
         }
 
         @Override
-        public int getCount() {
-            return mItems.size();
-        }
-
-        @Override
-        public NavigationMenuItem getItem(int position) {
-            return mItems.get(position);
-        }
-
-        @Override
         public long getItemId(int position) {
             return position;
         }
 
         @Override
-        public int getViewTypeCount() {
-            return 3;
+        public int getItemCount() {
+            return mItems.size();
         }
 
         @Override
         public int getItemViewType(int position) {
-            NavigationMenuItem item = getItem(position);
-            if (item.isSeparator()) {
+            NavigationMenuItem item = mItems.get(position);
+            if (item instanceof NavigationMenuSeparatorItem) {
                 return VIEW_TYPE_SEPARATOR;
-            } else if (item.getMenuItem().hasSubMenu()) {
-                return VIEW_TYPE_SUBHEADER;
-            } else {
-                return VIEW_TYPE_NORMAL;
+            } else if (item instanceof NavigationMenuHeaderItem) {
+                return VIEW_TYPE_HEADER;
+            } else if (item instanceof NavigationMenuTextItem) {
+                NavigationMenuTextItem textItem = (NavigationMenuTextItem) item;
+                if (textItem.getMenuItem().hasSubMenu()) {
+                    return VIEW_TYPE_SUBHEADER;
+                } else {
+                    return VIEW_TYPE_NORMAL;
+                }
             }
+            throw new RuntimeException("Unknown item type.");
         }
 
         @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            NavigationMenuItem item = getItem(position);
-            int viewType = getItemViewType(position);
+        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
             switch (viewType) {
                 case VIEW_TYPE_NORMAL:
-                    if (convertView == null) {
-                        convertView = mLayoutInflater.inflate(R.layout.design_navigation_item,
-                                parent, false);
-                    }
-                    NavigationMenuItemView itemView = (NavigationMenuItemView) convertView;
+                    return new NormalViewHolder(mLayoutInflater, parent, mOnClickListener);
+                case VIEW_TYPE_SUBHEADER:
+                    return new SubheaderViewHolder(mLayoutInflater, parent);
+                case VIEW_TYPE_SEPARATOR:
+                    return new SeparatorViewHolder(mLayoutInflater, parent);
+                case VIEW_TYPE_HEADER:
+                    return new HeaderViewHolder(mHeaderLayout);
+            }
+            return null;
+        }
+
+        @Override
+        public void onBindViewHolder(ViewHolder holder, int position) {
+            switch (getItemViewType(position)) {
+                case VIEW_TYPE_NORMAL: {
+                    NavigationMenuItemView itemView = (NavigationMenuItemView) holder.itemView;
                     itemView.setIconTintList(mIconTintList);
                     if (mTextAppearanceSet) {
                         itemView.setTextAppearance(itemView.getContext(), mTextAppearance);
@@ -331,42 +391,40 @@
                     }
                     itemView.setBackgroundDrawable(mItemBackground != null ?
                             mItemBackground.getConstantState().newDrawable() : null);
+                    NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
                     itemView.initialize(item.getMenuItem(), 0);
                     break;
-                case VIEW_TYPE_SUBHEADER:
-                    if (convertView == null) {
-                        convertView = mLayoutInflater.inflate(
-                                R.layout.design_navigation_item_subheader, parent, false);
-                    }
-                    TextView subHeader = (TextView) convertView;
+                }
+                case VIEW_TYPE_SUBHEADER: {
+                    TextView subHeader = (TextView) holder.itemView;
+                    NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
                     subHeader.setText(item.getMenuItem().getTitle());
                     break;
-                case VIEW_TYPE_SEPARATOR:
-                    if (convertView == null) {
-                        convertView = mLayoutInflater.inflate(
-                                R.layout.design_navigation_item_separator, parent, false);
-                    }
-                    convertView.setPadding(0, item.getPaddingTop(), 0,
+                }
+                case VIEW_TYPE_SEPARATOR: {
+                    NavigationMenuSeparatorItem item =
+                            (NavigationMenuSeparatorItem) mItems.get(position);
+                    holder.itemView.setPadding(0, item.getPaddingTop(), 0,
                             item.getPaddingBottom());
                     break;
+                }
+                case VIEW_TYPE_HEADER: {
+                    break;
+                }
             }
-            return convertView;
+
         }
 
         @Override
-        public boolean areAllItemsEnabled() {
-            return false;
+        public void onViewRecycled(ViewHolder holder) {
+            if (holder instanceof NormalViewHolder) {
+                ((NavigationMenuItemView) holder.itemView).recycle();
+            }
         }
 
-        @Override
-        public boolean isEnabled(int position) {
-            return getItem(position).isEnabled();
-        }
-
-        @Override
-        public void notifyDataSetChanged() {
+        public void update() {
             prepareMenuItems();
-            super.notifyDataSetChanged();
+            notifyDataSetChanged();
         }
 
         /**
@@ -379,6 +437,8 @@
             }
             mUpdateSuspended = true;
             mItems.clear();
+            mItems.add(new NavigationMenuHeaderItem());
+
             int currentGroupId = -1;
             int currentGroupStart = 0;
             boolean currentGroupHasIcon = false;
@@ -394,9 +454,9 @@
                     SubMenu subMenu = item.getSubMenu();
                     if (subMenu.hasVisibleItems()) {
                         if (i != 0) {
-                            mItems.add(NavigationMenuItem.separator(mPaddingSeparator, 0));
+                            mItems.add(new NavigationMenuSeparatorItem(mPaddingSeparator, 0));
                         }
-                        mItems.add(NavigationMenuItem.of(item));
+                        mItems.add(new NavigationMenuTextItem(item));
                         boolean subMenuHasIcon = false;
                         int subMenuStart = mItems.size();
                         for (int j = 0, size = subMenu.size(); j < size; j++) {
@@ -411,7 +471,7 @@
                                 if (item.isChecked()) {
                                     setCheckedItem(item);
                                 }
-                                mItems.add(NavigationMenuItem.of(subMenuItem));
+                                mItems.add(new NavigationMenuTextItem(subMenuItem));
                             }
                         }
                         if (subMenuHasIcon) {
@@ -425,7 +485,7 @@
                         currentGroupHasIcon = item.getIcon() != null;
                         if (i != 0) {
                             currentGroupStart++;
-                            mItems.add(NavigationMenuItem.separator(
+                            mItems.add(new NavigationMenuSeparatorItem(
                                     mPaddingSeparator, mPaddingSeparator));
                         }
                     } else if (!currentGroupHasIcon && item.getIcon() != null) {
@@ -435,7 +495,7 @@
                     if (currentGroupHasIcon && item.getIcon() == null) {
                         item.setIcon(android.R.color.transparent);
                     }
-                    mItems.add(NavigationMenuItem.of(item));
+                    mItems.add(new NavigationMenuTextItem(item));
                     currentGroupId = groupId;
                 }
             }
@@ -444,7 +504,8 @@
 
         private void appendTransparentIconIfMissing(int startIndex, int endIndex) {
             for (int i = startIndex; i < endIndex; i++) {
-                MenuItem item = mItems.get(i).getMenuItem();
+                NavigationMenuTextItem textItem = (NavigationMenuTextItem) mItems.get(i);
+                MenuItem item = textItem.getMenuItem();
                 if (item.getIcon() == null) {
                     if (mTransparentIcon == null) {
                         mTransparentIcon = new ColorDrawable(android.R.color.transparent);
@@ -470,6 +531,20 @@
             if (mCheckedItem != null) {
                 state.putInt(STATE_CHECKED_ITEM, mCheckedItem.getItemId());
             }
+            // Store the states of the action views.
+            SparseArray<ParcelableSparseArray> actionViewStates = new SparseArray<>();
+            for (NavigationMenuItem navigationMenuItem : mItems) {
+                if (navigationMenuItem instanceof NavigationMenuTextItem) {
+                    MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
+                    View actionView = item != null ? item.getActionView() : null;
+                    if (actionView != null) {
+                        ParcelableSparseArray container = new ParcelableSparseArray();
+                        actionView.saveHierarchyState(container);
+                        actionViewStates.put(item.getItemId(), container);
+                    }
+                }
+            }
+            state.putSparseParcelableArray(STATE_ACTION_VIEWS, actionViewStates);
             return state;
         }
 
@@ -478,15 +553,29 @@
             if (checkedItem != 0) {
                 mUpdateSuspended = true;
                 for (NavigationMenuItem item : mItems) {
-                    MenuItemImpl menuItem = item.getMenuItem();
-                    if (menuItem !=  null && menuItem.getItemId() == checkedItem) {
-                        setCheckedItem(menuItem);
-                        break;
+                    if (item instanceof NavigationMenuTextItem) {
+                        MenuItemImpl menuItem = ((NavigationMenuTextItem) item).getMenuItem();
+                        if (menuItem != null && menuItem.getItemId() == checkedItem) {
+                            setCheckedItem(menuItem);
+                            break;
+                        }
                     }
                 }
                 mUpdateSuspended = false;
                 prepareMenuItems();
             }
+            // Restore the states of the action views.
+            SparseArray<ParcelableSparseArray> actionViewStates = state
+                    .getSparseParcelableArray(STATE_ACTION_VIEWS);
+            for (NavigationMenuItem navigationMenuItem : mItems) {
+                if (navigationMenuItem instanceof NavigationMenuTextItem) {
+                    MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
+                    View actionView = item != null ? item.getActionView() : null;
+                    if (actionView != null) {
+                        actionView.restoreHierarchyState(actionViewStates.get(item.getItemId()));
+                    }
+                }
+            }
         }
 
         public void setUpdateSuspended(boolean updateSuspended) {
@@ -496,37 +585,42 @@
     }
 
     /**
-     * Wraps {@link MenuItemImpl}. This allows separators to be counted as items in list.
+     * Unified data model for all sorts of navigation menu items.
      */
-    private static class NavigationMenuItem {
+    private interface NavigationMenuItem {
+    }
 
-        /** The item; null for separators */
+    /**
+     * Normal or subheader items.
+     */
+    private static class NavigationMenuTextItem implements NavigationMenuItem {
+
         private final MenuItemImpl mMenuItem;
 
-        /** Padding top; used only for separators */
+        private NavigationMenuTextItem(MenuItemImpl item) {
+            mMenuItem = item;
+        }
+
+        public MenuItemImpl getMenuItem() {
+            return mMenuItem;
+        }
+
+    }
+
+    /**
+     * Separator items.
+     */
+    private static class NavigationMenuSeparatorItem implements NavigationMenuItem {
+
         private final int mPaddingTop;
 
-        /** Padding bottom; used only for separators */
         private final int mPaddingBottom;
 
-        private NavigationMenuItem(MenuItemImpl item, int paddingTop, int paddingBottom) {
-            mMenuItem = item;
+        public NavigationMenuSeparatorItem(int paddingTop, int paddingBottom) {
             mPaddingTop = paddingTop;
             mPaddingBottom = paddingBottom;
         }
 
-        public static NavigationMenuItem of(MenuItemImpl item) {
-            return new NavigationMenuItem(item, 0, 0);
-        }
-
-        public static NavigationMenuItem separator(int paddingTop, int paddingBottom) {
-            return new NavigationMenuItem(null, paddingTop, paddingBottom);
-        }
-
-        public boolean isSeparator() {
-            return mMenuItem == null;
-        }
-
         public int getPaddingTop() {
             return mPaddingTop;
         }
@@ -535,15 +629,13 @@
             return mPaddingBottom;
         }
 
-        public MenuItemImpl getMenuItem() {
-            return mMenuItem;
-        }
+    }
 
-        public boolean isEnabled() {
-            // Separators and subheaders never respond to click
-            return mMenuItem != null && !mMenuItem.hasSubMenu() && mMenuItem.isEnabled();
-        }
-
+    /**
+     * Header (not subheader) items.
+     */
+    private static class NavigationMenuHeaderItem implements NavigationMenuItem {
+        // The actual content is hold by NavigationMenuPresenter#mHeaderLayout.
     }
 
 }
diff --git a/design/src/android/support/design/internal/NavigationMenuView.java b/design/src/android/support/design/internal/NavigationMenuView.java
index 054b800..c7c90c3 100644
--- a/design/src/android/support/design/internal/NavigationMenuView.java
+++ b/design/src/android/support/design/internal/NavigationMenuView.java
@@ -17,15 +17,16 @@
 package android.support.design.internal;
 
 import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuView;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
-import android.widget.ListView;
 
 /**
  * @hide
  */
-public class NavigationMenuView extends ListView implements MenuView {
+public class NavigationMenuView extends RecyclerView implements MenuView {
 
     public NavigationMenuView(Context context) {
         this(context, null);
@@ -37,6 +38,7 @@
 
     public NavigationMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
     }
 
     @Override
diff --git a/design/src/android/support/design/internal/NavigationSubMenu.java b/design/src/android/support/design/internal/NavigationSubMenu.java
index ae59412..f17536f 100644
--- a/design/src/android/support/design/internal/NavigationSubMenu.java
+++ b/design/src/android/support/design/internal/NavigationSubMenu.java
@@ -17,10 +17,9 @@
 package android.support.design.internal;
 
 import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.view.MenuItem;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.SubMenuBuilder;
 
 /**
  * This is a {@link SubMenuBuilder} that it notifies the parent {@link NavigationMenu} of its menu
@@ -35,35 +34,9 @@
     }
 
     @Override
-    public MenuItem add(CharSequence title) {
-        MenuItem item = super.add(title);
-        notifyParent();
-        return item;
-    }
-
-    @Override
-    public MenuItem add(int titleRes) {
-        MenuItem item = super.add(titleRes);
-        notifyParent();
-        return item;
-    }
-
-    @Override
-    public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
-        MenuItem item = super.add(groupId, itemId, order, title);
-        notifyParent();
-        return item;
-    }
-
-    @Override
-    public MenuItem add(int groupId, int itemId, int order, int titleRes) {
-        MenuItem item = super.add(groupId, itemId, order, titleRes);
-        notifyParent();
-        return item;
-    }
-
-    private void notifyParent() {
-        ((MenuBuilder) getParentMenu()).onItemsChanged(true);
+    public void onItemsChanged(boolean structureChanged) {
+        super.onItemsChanged(structureChanged);
+        ((MenuBuilder) getParentMenu()).onItemsChanged(structureChanged);
     }
 
 }
diff --git a/design/src/android/support/design/internal/ParcelableSparseArray.java b/design/src/android/support/design/internal/ParcelableSparseArray.java
new file mode 100644
index 0000000..588950b
--- /dev/null
+++ b/design/src/android/support/design/internal/ParcelableSparseArray.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
+import android.util.SparseArray;
+
+/**
+ * @hide
+ */
+public class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
+
+    public ParcelableSparseArray() {
+        super();
+    }
+
+    public ParcelableSparseArray(Parcel source, ClassLoader loader) {
+        super();
+        int size = source.readInt();
+        int[] keys = new int[size];
+        source.readIntArray(keys);
+        Parcelable[] values = source.readParcelableArray(loader);
+        for (int i = 0; i < size; ++i) {
+            put(keys[i], values[i]);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        int size = size();
+        int[] keys = new int[size];
+        Parcelable[] values = new Parcelable[size];
+        for (int i = 0; i < size; ++i) {
+            keys[i] = keyAt(i);
+            values[i] = valueAt(i);
+        }
+        parcel.writeInt(size);
+        parcel.writeIntArray(keys);
+        parcel.writeParcelableArray(values, flags);
+    }
+
+    public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
+            ParcelableCompat
+                    .newCreator(new ParcelableCompatCreatorCallbacks<ParcelableSparseArray>() {
+                        @Override
+                        public ParcelableSparseArray createFromParcel(Parcel source,
+                                ClassLoader loader) {
+                            return new ParcelableSparseArray(source, loader);
+                        }
+
+                        @Override
+                        public ParcelableSparseArray[] newArray(int size) {
+                            return new ParcelableSparseArray[size];
+                        }
+                    });
+}
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
index 53e96ba..eb7a962 100644
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ b/design/src/android/support/design/widget/AppBarLayout.java
@@ -21,15 +21,15 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.design.R;
-import android.support.v4.view.MotionEventCompat;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.WindowInsetsCompat;
-import android.support.v4.widget.ScrollerCompat;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
@@ -142,6 +142,8 @@
         super(context, attrs);
         setOrientation(VERTICAL);
 
+        ThemeUtils.checkAppCompatTheme(context);
+
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
                 0, R.style.Widget_Design_AppBarLayout);
         mTargetElevation = a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0);
@@ -194,13 +196,15 @@
     }
 
     @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        invalidateScrollRanges();
+    }
+
+    @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-
-        // Invalidate the scroll ranges
-        mTotalScrollRange = INVALID_SCROLL_RANGE;
-        mDownPreScrollRange = INVALID_SCROLL_RANGE;
-        mDownPreScrollRange = INVALID_SCROLL_RANGE;
+        invalidateScrollRanges();
 
         mHaveChildWithInterpolator = false;
         for (int i = 0, z = getChildCount(); i < z; i++) {
@@ -215,6 +219,13 @@
         }
     }
 
+    private void invalidateScrollRanges() {
+        // Invalidate the scroll ranges
+        mTotalScrollRange = INVALID_SCROLL_RANGE;
+        mDownPreScrollRange = INVALID_SCROLL_RANGE;
+        mDownScrollRange = INVALID_SCROLL_RANGE;
+    }
+
     @Override
     public void setOrientation(int orientation) {
         if (orientation != VERTICAL) {
@@ -283,7 +294,7 @@
         return new LayoutParams(p);
     }
 
-    final boolean hasChildWithInterpolator() {
+    private boolean hasChildWithInterpolator() {
         return mHaveChildWithInterpolator;
     }
 
@@ -301,9 +312,7 @@
         for (int i = 0, z = getChildCount(); i < z; i++) {
             final View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final int childHeight = ViewCompat.isLaidOut(child)
-                    ? child.getHeight()
-                    : child.getMeasuredHeight();
+            final int childHeight = child.getMeasuredHeight();
             final int flags = lp.mScrollFlags;
 
             if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
@@ -323,25 +332,24 @@
                 break;
             }
         }
-        final int top = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
-        return mTotalScrollRange = (range - top);
+        return mTotalScrollRange = Math.max(0, range - getTopInset());
     }
 
-    final boolean hasScrollableChildren() {
+    private boolean hasScrollableChildren() {
         return getTotalScrollRange() != 0;
     }
 
     /**
      * Return the scroll range when scrolling up from a nested pre-scroll.
      */
-    final int getUpNestedPreScrollRange() {
+    private int getUpNestedPreScrollRange() {
         return getTotalScrollRange();
     }
 
     /**
      * Return the scroll range when scrolling down from a nested pre-scroll.
      */
-    final int getDownNestedPreScrollRange() {
+    private int getDownNestedPreScrollRange() {
         if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
             // If we already have a valid value, return it
             return mDownPreScrollRange;
@@ -351,9 +359,7 @@
         for (int i = getChildCount() - 1; i >= 0; i--) {
             final View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final int childHeight = ViewCompat.isLaidOut(child)
-                    ? child.getHeight()
-                    : child.getMeasuredHeight();
+            final int childHeight = child.getMeasuredHeight();
             final int flags = lp.mScrollFlags;
 
             if ((flags & LayoutParams.FLAG_QUICK_RETURN) == LayoutParams.FLAG_QUICK_RETURN) {
@@ -363,6 +369,9 @@
                 if ((flags & LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED) != 0) {
                     // If they're set to enter collapsed, use the minimum height
                     range += ViewCompat.getMinimumHeight(child);
+                } else if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
+                    // Only enter by the amount of the collapsed height
+                    range += childHeight - ViewCompat.getMinimumHeight(child);
                 } else {
                     // Else use the full height
                     range += childHeight;
@@ -373,13 +382,13 @@
                 break;
             }
         }
-        return mDownPreScrollRange = range;
+        return mDownPreScrollRange = Math.max(0, range - getTopInset());
     }
 
     /**
      * Return the scroll range when scrolling down from a nested scroll.
      */
-    final int getDownNestedScrollRange() {
+    private int getDownNestedScrollRange() {
         if (mDownScrollRange != INVALID_SCROLL_RANGE) {
             // If we already have a valid value, return it
             return mDownScrollRange;
@@ -389,9 +398,7 @@
         for (int i = 0, z = getChildCount(); i < z; i++) {
             final View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            int childHeight = ViewCompat.isLaidOut(child)
-                    ? child.getHeight()
-                    : child.getMeasuredHeight();
+            int childHeight = child.getMeasuredHeight();
             childHeight += lp.topMargin + lp.bottomMargin;
 
             final int flags = lp.mScrollFlags;
@@ -402,9 +409,10 @@
 
                 if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
                     // For a collapsing exit scroll, we to take the collapsed height into account.
-                    // We also return the range straight away since later views can't scroll
+                    // We also break the range straight away since later views can't scroll
                     // beneath us
-                    return range - ViewCompat.getMinimumHeight(child);
+                    range -= ViewCompat.getMinimumHeight(child) + getTopInset();
+                    break;
                 }
             } else {
                 // As soon as a view doesn't have the scroll flag, we end the range calculation.
@@ -412,7 +420,7 @@
                 break;
             }
         }
-        return mDownScrollRange = range;
+        return mDownScrollRange = Math.max(0, range);
     }
 
     final int getMinimumHeightForVisibleOverlappingContent() {
@@ -454,14 +462,18 @@
         return mTargetElevation;
     }
 
-    int getPendingAction() {
+    private int getPendingAction() {
         return mPendingAction;
     }
 
-    void resetPendingAction() {
+    private void resetPendingAction() {
         mPendingAction = PENDING_ACTION_NONE;
     }
 
+    private int getTopInset() {
+        return mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
+    }
+
     private void setWindowInsets(WindowInsetsCompat insets) {
         // Invalidate the total scroll range...
         mTotalScrollRange = INVALID_SCROLL_RANGE;
@@ -484,7 +496,8 @@
                 SCROLL_FLAG_SCROLL,
                 SCROLL_FLAG_EXIT_UNTIL_COLLAPSED,
                 SCROLL_FLAG_ENTER_ALWAYS,
-                SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED
+                SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED,
+                SCROLL_FLAG_SNAP
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface ScrollFlags {}
@@ -524,9 +537,18 @@
         public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 0x8;
 
         /**
-         * Internal flag which allows quick checking of 'quick return'
+         * Upon a scroll ending, if the view is only partially visible then it will be snapped
+         * and scrolled to it's closest edge. For example, if the view only has it's bottom 25%
+         * displayed, it will be scrolled off screen completely. Conversely, if it's bottom 75%
+         * is visible then it will be scrolled fully into view.
+         */
+        public static final int SCROLL_FLAG_SNAP = 0x10;
+
+        /**
+         * Internal flags which allows quick checking features
          */
         static final int FLAG_QUICK_RETURN = SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS;
+        static final int FLAG_SNAP = SCROLL_FLAG_SCROLL | SCROLL_FLAG_SNAP;
 
         int mScrollFlags = SCROLL_FLAG_SCROLL;
         Interpolator mScrollInterpolator;
@@ -574,8 +596,8 @@
          * Set the scrolling flags.
          *
          * @param flags bitwise int of {@link #SCROLL_FLAG_SCROLL},
-         *             {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS}
-         *             and {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED}.
+         *             {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS},
+         *             {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED} and {@link #SCROLL_FLAG_SNAP }.
          *
          * @see #getScrollFlags()
          *
@@ -626,15 +648,30 @@
      * The default {@link Behavior} for {@link AppBarLayout}. Implements the necessary nested
      * scroll handling with offsetting.
      */
-    public static class Behavior extends ViewOffsetBehavior<AppBarLayout> {
-        private static final int INVALID_POINTER = -1;
+    public static class Behavior extends HeaderBehavior<AppBarLayout> {
+        private static final int ANIMATE_OFFSET_DIPS_PER_SECOND = 300;
         private static final int INVALID_POSITION = -1;
 
+        /**
+         * Callback to allow control over any {@link AppBarLayout} dragging.
+         */
+        public static abstract class DragCallback {
+            /**
+             * Allows control over whether the given {@link AppBarLayout} can be dragged or not.
+             *
+             * <p>Dragging is defined as a direct touch on the AppBarLayout with movement. This
+             * call does not affect any nested scrolling.</p>
+             *
+             * @return true if we are in a position to scroll the AppBarLayout via a drag, false
+             *         if not.
+             */
+            public abstract boolean canDrag(@NonNull AppBarLayout appBarLayout);
+        }
+
         private int mOffsetDelta;
 
         private boolean mSkipNestedPreScroll;
-        private Runnable mFlingRunnable;
-        private ScrollerCompat mScroller;
+        private boolean mWasNestedFlung;
 
         private ValueAnimatorCompat mAnimator;
 
@@ -642,12 +679,8 @@
         private boolean mOffsetToChildIndexOnLayoutIsMinHeight;
         private float mOffsetToChildIndexOnLayoutPerc;
 
-        private boolean mIsBeingDragged;
-        private int mActivePointerId = INVALID_POINTER;
-        private int mLastMotionY;
-        private int mTouchSlop = -1;
-
         private WeakReference<View> mLastNestedScrollingChildRef;
+        private DragCallback mOnDragCallback;
 
         public Behavior() {}
 
@@ -711,173 +744,85 @@
         }
 
         @Override
-        public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
+        public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl,
                 View target) {
-            // Reset the skip flag
+            if (!mWasNestedFlung) {
+                // If we haven't been flung then let's see if the current view has been set to snap
+                snapToChildIfNeeded(coordinatorLayout, abl);
+            }
+
+            // Reset the flags
             mSkipNestedPreScroll = false;
+            mWasNestedFlung = false;
             // Keep a reference to the previous nested scrolling child
             mLastNestedScrollingChildRef = new WeakReference<>(target);
         }
 
         @Override
-        public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child,
-                MotionEvent ev) {
-            if (mTouchSlop < 0) {
-                mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
-            }
-
-            final int action = ev.getAction();
-
-            // Shortcut since we're being dragged
-            if (action == MotionEvent.ACTION_MOVE && mIsBeingDragged) {
-                return true;
-            }
-
-            switch (MotionEventCompat.getActionMasked(ev)) {
-                case MotionEvent.ACTION_MOVE: {
-                    final int activePointerId = mActivePointerId;
-                    if (activePointerId == INVALID_POINTER) {
-                        // If we don't have a valid id, the touch down wasn't on content.
-                        break;
-                    }
-                    final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
-                    if (pointerIndex == -1) {
-                        break;
-                    }
-
-                    final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
-                    final int yDiff = Math.abs(y - mLastMotionY);
-                    if (yDiff > mTouchSlop) {
-                        mIsBeingDragged = true;
-                        mLastMotionY = y;
-                    }
-                    break;
-                }
-
-                case MotionEvent.ACTION_DOWN: {
-                    mIsBeingDragged = false;
-                    final int x = (int) ev.getX();
-                    final int y = (int) ev.getY();
-                    if (parent.isPointInChildBounds(child, x, y) && canDragAppBarLayout()) {
-                        mLastMotionY = y;
-                        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
-                    }
-                    break;
-                }
-
-                case MotionEvent.ACTION_CANCEL:
-                case MotionEvent.ACTION_UP:
-                    mIsBeingDragged = false;
-                    mActivePointerId = INVALID_POINTER;
-                    break;
-            }
-
-            return mIsBeingDragged;
-        }
-
-        @Override
-        public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
-            if (mTouchSlop < 0) {
-                mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
-            }
-
-            int x = (int) ev.getX();
-            int y = (int) ev.getY();
-
-            switch (MotionEventCompat.getActionMasked(ev)) {
-                case MotionEvent.ACTION_DOWN:
-                    if (parent.isPointInChildBounds(child, x, y) && canDragAppBarLayout()) {
-                        mLastMotionY = y;
-                        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
-                    } else {
-                        return false;
-                    }
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    final int activePointerIndex = MotionEventCompat.findPointerIndex(ev,
-                            mActivePointerId);
-                    if (activePointerIndex == -1) {
-                        return false;
-                    }
-
-                    y = (int) MotionEventCompat.getY(ev, activePointerIndex);
-
-                    int dy = mLastMotionY - y;
-                    if (!mIsBeingDragged && Math.abs(dy) > mTouchSlop) {
-                        mIsBeingDragged = true;
-                        if (dy > 0) {
-                            dy -= mTouchSlop;
-                        } else {
-                            dy += mTouchSlop;
-                        }
-                    }
-
-                    if (mIsBeingDragged) {
-                        mLastMotionY = y;
-                        // We're being dragged so scroll the ABL
-                        scroll(parent, child, dy, -child.getDownNestedScrollRange(), 0);
-                    }
-                    break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    mIsBeingDragged = false;
-                    mActivePointerId = INVALID_POINTER;
-                    break;
-            }
-
-            return true;
-        }
-
-        @Override
         public boolean onNestedFling(final CoordinatorLayout coordinatorLayout,
                 final AppBarLayout child, View target, float velocityX, float velocityY,
                 boolean consumed) {
+            boolean flung = false;
+
             if (!consumed) {
                 // It has been consumed so let's fling ourselves
-                return fling(coordinatorLayout, child, -child.getTotalScrollRange(), 0, -velocityY);
+                flung = fling(coordinatorLayout, child, -child.getTotalScrollRange(),
+                        0, -velocityY);
             } else {
                 // If we're scrolling up and the child also consumed the fling. We'll fake scroll
                 // upto our 'collapsed' offset
-                int targetScroll;
                 if (velocityY < 0) {
                     // We're scrolling down
-                    targetScroll = -child.getTotalScrollRange()
+                    final int targetScroll = -child.getTotalScrollRange()
                             + child.getDownNestedPreScrollRange();
-
-                    if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
-                        // If we're currently expanded more than the target scroll, we'll return false
-                        // now. This is so that we don't 'scroll' the wrong way.
-                        return false;
+                    if (getTopBottomOffsetForScrollingSibling() < targetScroll) {
+                        // If we're currently not expanded more than the target scroll, we'll
+                        // animate a fling
+                        animateOffsetTo(coordinatorLayout, child, targetScroll);
+                        flung = true;
                     }
                 } else {
                     // We're scrolling up
-                    targetScroll = -child.getUpNestedPreScrollRange();
-
-                    if (getTopBottomOffsetForScrollingSibling() < targetScroll) {
-                        // If we're currently expanded less than the target scroll, we'll return
-                        // false now. This is so that we don't 'scroll' the wrong way.
-                        return false;
+                    final int targetScroll = -child.getUpNestedPreScrollRange();
+                    if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
+                        // If we're currently not expanded less than the target scroll, we'll
+                        // animate a fling
+                        animateOffsetTo(coordinatorLayout, child, targetScroll);
+                        flung = true;
                     }
                 }
-
-                if (getTopBottomOffsetForScrollingSibling() != targetScroll) {
-                    animateOffsetTo(coordinatorLayout, child, targetScroll);
-                    return true;
-                }
             }
 
-            return false;
+            mWasNestedFlung = flung;
+            return flung;
+        }
+
+        /**
+         * Set a callback to control any {@link AppBarLayout} dragging.
+         *
+         * @param callback the callback to use, or {@code null} to use the default behavior.
+         */
+        public void setDragCallback(@Nullable DragCallback callback) {
+            mOnDragCallback = callback;
         }
 
         private void animateOffsetTo(final CoordinatorLayout coordinatorLayout,
-                final AppBarLayout child, int offset) {
+                final AppBarLayout child, final int offset) {
+            final int currentOffset = getTopBottomOffsetForScrollingSibling();
+            if (currentOffset == offset) {
+                if (mAnimator != null && mAnimator.isRunning()) {
+                    mAnimator.cancel();
+                }
+                return;
+            }
+
             if (mAnimator == null) {
                 mAnimator = ViewUtils.createAnimator();
                 mAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
                 mAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
                     @Override
                     public void onAnimationUpdate(ValueAnimatorCompat animator) {
-                        setAppBarTopBottomOffset(coordinatorLayout, child,
+                        setHeaderTopBottomOffset(coordinatorLayout, child,
                                 animator.getAnimatedIntValue());
                     }
                 });
@@ -885,52 +830,45 @@
                 mAnimator.cancel();
             }
 
-            mAnimator.setIntValues(getTopBottomOffsetForScrollingSibling(), offset);
+            // Set the duration based on the amount of dips we're travelling in
+            final float distanceDp = Math.abs(currentOffset - offset) /
+                    coordinatorLayout.getResources().getDisplayMetrics().density;
+            mAnimator.setDuration(Math.round(distanceDp * 1000 / ANIMATE_OFFSET_DIPS_PER_SECOND));
+
+            mAnimator.setIntValues(currentOffset, offset);
             mAnimator.start();
         }
 
-        private boolean fling(CoordinatorLayout coordinatorLayout, AppBarLayout layout, int minOffset,
-                int maxOffset, float velocityY) {
-            if (mFlingRunnable != null) {
-                layout.removeCallbacks(mFlingRunnable);
+        private View getChildOnOffset(AppBarLayout abl, final int offset) {
+            for (int i = 0, count = abl.getChildCount(); i < count; i++) {
+                View child = abl.getChildAt(i);
+                if (child.getTop() <= -offset && child.getBottom() >= -offset) {
+                    return child;
+                }
             }
-
-            if (mScroller == null) {
-                mScroller = ScrollerCompat.create(layout.getContext());
-            }
-
-            mScroller.fling(
-                    0, getTopBottomOffsetForScrollingSibling(), // curr
-                    0, Math.round(velocityY), // velocity.
-                    0, 0, // x
-                    minOffset, maxOffset); // y
-
-            if (mScroller.computeScrollOffset()) {
-                mFlingRunnable = new FlingRunnable(coordinatorLayout, layout);
-                ViewCompat.postOnAnimation(layout, mFlingRunnable);
-                return true;
-            } else {
-                mFlingRunnable = null;
-                return false;
-            }
+            return null;
         }
 
-        private class FlingRunnable implements Runnable {
-            private final CoordinatorLayout mParent;
-            private final AppBarLayout mLayout;
+        private void snapToChildIfNeeded(CoordinatorLayout coordinatorLayout, AppBarLayout abl) {
+            final int offset = getTopBottomOffsetForScrollingSibling();
+            final View offsetChild = getChildOnOffset(abl, offset);
+            if (offsetChild != null) {
+                final LayoutParams lp = (LayoutParams) offsetChild.getLayoutParams();
+                if ((lp.getScrollFlags() & LayoutParams.FLAG_SNAP) == LayoutParams.FLAG_SNAP) {
+                    // We're set the snap, so animate the offset to the nearest edge
+                    int childTop = -offsetChild.getTop();
+                    int childBottom = -offsetChild.getBottom();
 
-            FlingRunnable(CoordinatorLayout parent, AppBarLayout layout) {
-                mParent = parent;
-                mLayout = layout;
-            }
+                    // If the view is set only exit until it is collapsed, we'll abide by that
+                    if ((lp.getScrollFlags() & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED)
+                            == LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) {
+                        childBottom += ViewCompat.getMinimumHeight(offsetChild);
+                    }
 
-            @Override
-            public void run() {
-                if (mLayout != null && mScroller != null && mScroller.computeScrollOffset()) {
-                    setAppBarTopBottomOffset(mParent, mLayout, mScroller.getCurrY());
-
-                    // Post ourselves so that we run on the next animation
-                    ViewCompat.postOnAnimation(mLayout, this);
+                    final int newOffset = offset < (childBottom + childTop) / 2
+                            ? childBottom : childTop;
+                    animateOffsetTo(coordinatorLayout, abl,
+                            MathUtils.constrain(newOffset, -abl.getTotalScrollRange(), 0));
                 }
             }
         }
@@ -948,17 +886,15 @@
                     if (animate) {
                         animateOffsetTo(parent, abl, offset);
                     } else {
-                        setAppBarTopBottomOffset(parent, abl, offset);
+                        setHeaderTopBottomOffset(parent, abl, offset);
                     }
                 } else if ((pendingAction & PENDING_ACTION_EXPANDED) != 0) {
                     if (animate) {
                         animateOffsetTo(parent, abl, 0);
                     } else {
-                        setAppBarTopBottomOffset(parent, abl, 0);
+                        setHeaderTopBottomOffset(parent, abl, 0);
                     }
                 }
-                // Finally reset the pending state
-                abl.resetPendingAction();
             } else if (mOffsetToChildIndexOnLayout >= 0) {
                 View child = abl.getChildAt(mOffsetToChildIndexOnLayout);
                 int offset = -child.getBottom();
@@ -968,45 +904,70 @@
                     offset += Math.round(child.getHeight() * mOffsetToChildIndexOnLayoutPerc);
                 }
                 setTopAndBottomOffset(offset);
-                mOffsetToChildIndexOnLayout = INVALID_POSITION;
             }
 
+            // Finally reset any pending states
+            abl.resetPendingAction();
+            mOffsetToChildIndexOnLayout = INVALID_POSITION;
+
+            // We may have changed size, so let's constrain the top and bottom offset correctly,
+            // just in case we're out of the bounds
+            setTopAndBottomOffset(
+                    MathUtils.constrain(getTopAndBottomOffset(), -abl.getTotalScrollRange(), 0));
+
             // Make sure we update the elevation
             dispatchOffsetUpdates(abl);
 
             return handled;
         }
 
-        private int scroll(CoordinatorLayout coordinatorLayout, AppBarLayout appBarLayout,
-                int dy, int minOffset, int maxOffset) {
-            return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout,
-                    getTopBottomOffsetForScrollingSibling() - dy, minOffset, maxOffset);
-        }
-
-        private boolean canDragAppBarLayout() {
-            if (mLastNestedScrollingChildRef != null) {
-                final View view = mLastNestedScrollingChildRef.get();
-                return view != null && view.isShown() && !ViewCompat.canScrollVertically(view, -1);
+        @Override
+        boolean canDragView(AppBarLayout view) {
+            if (mOnDragCallback != null) {
+                // If there is a drag callback set, it's in control
+                return mOnDragCallback.canDrag(view);
             }
-            return false;
+
+            // Else we'll use the default behaviour of seeing if it can scroll down
+            if (mLastNestedScrollingChildRef != null) {
+                // If we have a reference to a scrolling view, check it
+                final View scrollingView = mLastNestedScrollingChildRef.get();
+                return scrollingView != null && scrollingView.isShown()
+                        && !ViewCompat.canScrollVertically(scrollingView, -1);
+            } else {
+                // Otherwise we assume that the scrolling view hasn't been scrolled and can drag.
+                return true;
+            }
         }
 
-        final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
-                AppBarLayout appBarLayout, int newOffset) {
-            return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout, newOffset,
-                    Integer.MIN_VALUE, Integer.MAX_VALUE);
+        @Override
+        void onFlingFinished(CoordinatorLayout parent, AppBarLayout layout) {
+            // At the end of a manual fling, check to see if we need to snap to the edge-child
+            snapToChildIfNeeded(parent, layout);
         }
 
-        final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
-                AppBarLayout appBarLayout, int newOffset, int minOffset, int maxOffset) {
+        @Override
+        int getMaxDragOffset(AppBarLayout view) {
+            return -view.getDownNestedScrollRange();
+        }
+
+        @Override
+        int getScrollRangeForDragFling(AppBarLayout view) {
+            return view.getTotalScrollRange();
+        }
+
+        @Override
+        int setHeaderTopBottomOffset(CoordinatorLayout coordinatorLayout,
+                AppBarLayout header, int newOffset, int minOffset, int maxOffset) {
             final int curOffset = getTopBottomOffsetForScrollingSibling();
             int consumed = 0;
 
-            if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
+            if (minOffset != 0 && curOffset >= minOffset
+                    && curOffset <= maxOffset) {
                 // If we have some scrolling range, and we're currently within the min and max
                 // offsets, calculate a new offset
                 newOffset = MathUtils.constrain(newOffset, minOffset, maxOffset);
-
+                AppBarLayout appBarLayout = (AppBarLayout) header;
                 if (curOffset != newOffset) {
                     final int interpolatedOffset = appBarLayout.hasChildWithInterpolator()
                             ? interpolateOffset(appBarLayout, newOffset)
@@ -1072,6 +1033,10 @@
                             }
                         }
 
+                        if (ViewCompat.getFitsSystemWindows(child)) {
+                            childScrollableHeight -= layout.getTopInset();
+                        }
+
                         if (childScrollableHeight > 0) {
                             final int offsetForView = absOffset - child.getTop();
                             final int interpolatedDiff = Math.round(childScrollableHeight *
@@ -1091,7 +1056,8 @@
             return offset;
         }
 
-        final int getTopBottomOffsetForScrollingSibling() {
+        @Override
+        int getTopBottomOffsetForScrollingSibling() {
             return getTopAndBottomOffset() + mOffsetDelta;
         }
 
@@ -1134,12 +1100,12 @@
             }
         }
 
-        protected static class SavedState extends View.BaseSavedState {
+        protected static class SavedState extends BaseSavedState {
             int firstVisibleChildIndex;
             float firstVisibileChildPercentageShown;
             boolean firstVisibileChildAtMinimumHeight;
 
-            public SavedState(Parcel source) {
+            public SavedState(Parcel source, ClassLoader loader) {
                 super(source);
                 firstVisibleChildIndex = source.readInt();
                 firstVisibileChildPercentageShown = source.readFloat();
@@ -1159,17 +1125,17 @@
             }
 
             public static final Parcelable.Creator<SavedState> CREATOR =
-                    new Parcelable.Creator<SavedState>() {
+                    ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
                         @Override
-                        public SavedState createFromParcel(Parcel source) {
-                            return new SavedState(source);
+                        public SavedState createFromParcel(Parcel source, ClassLoader loader) {
+                            return new SavedState(source, loader);
                         }
 
                         @Override
                         public SavedState[] newArray(int size) {
                             return new SavedState[size];
                         }
-                    };
+                    });
         }
     }
 
@@ -1177,7 +1143,7 @@
      * Behavior which should be used by {@link View}s which can scroll vertically and support
      * nested scrolling to automatically scroll any {@link AppBarLayout} siblings.
      */
-    public static class ScrollingViewBehavior extends ViewOffsetBehavior<View> {
+    public static class ScrollingViewBehavior extends HeaderScrollingViewBehavior {
         private int mOverlayTop;
 
         public ScrollingViewBehavior() {}
@@ -1199,78 +1165,64 @@
         }
 
         @Override
-        public boolean onMeasureChild(CoordinatorLayout parent, View child,
-                int parentWidthMeasureSpec, int widthUsed,
-                int parentHeightMeasureSpec, int heightUsed) {
-            final int childLpHeight = child.getLayoutParams().height;
-            if (childLpHeight == LayoutParams.MATCH_PARENT
-                    || childLpHeight == LayoutParams.WRAP_CONTENT) {
-                // If the child's height is set to match_parent/wrap_content then measure it
-                // with the maximum visible height
+        public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
+            // First lay out the child as normal
+            super.onLayoutChild(parent, child, layoutDirection);
 
-                final List<View> dependencies = parent.getDependencies(child);
-                if (dependencies.isEmpty()) {
-                    // If we don't have any dependencies, return false
-                    return false;
-                }
-
-                final AppBarLayout appBar = findFirstAppBarLayout(dependencies);
-                if (appBar != null && ViewCompat.isLaidOut(appBar)) {
-                    if (ViewCompat.getFitsSystemWindows(appBar)) {
-                        // If the AppBarLayout is fitting system windows then we need to also,
-                        // otherwise we'll get CoL's compatible layout functionality
-                        ViewCompat.setFitsSystemWindows(child, true);
-                    }
-
-                    int availableHeight = MeasureSpec.getSize(parentHeightMeasureSpec);
-                    if (availableHeight == 0) {
-                        // If the measure spec doesn't specify a size, use the current height
-                        availableHeight = parent.getHeight();
-                    }
-                    final int height = availableHeight - appBar.getMeasuredHeight()
-                            + appBar.getTotalScrollRange();
-                    final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
-                            childLpHeight == LayoutParams.MATCH_PARENT
-                                    ? MeasureSpec.EXACTLY
-                                    : MeasureSpec.AT_MOST);
-
-                    // Now measure the scrolling child with the correct height
-                    parent.onMeasureChild(child, parentWidthMeasureSpec,
-                            widthUsed, heightMeasureSpec, heightUsed);
-
-                    return true;
+            // Now offset us correctly to be in the correct position. This is important for things
+            // like activity transitions which rely on accurate positioning after the first layout.
+            final List<View> dependencies = parent.getDependencies(child);
+            for (int i = 0, z = dependencies.size(); i < z; i++) {
+                if (updateOffset(parent, child, dependencies.get(i))) {
+                    // If we updated the offset, break out of the loop now
+                    break;
                 }
             }
-            return false;
+            return true;
         }
 
         @Override
         public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
                 View dependency) {
+            updateOffset(parent, child, dependency);
+            return false;
+        }
+
+        private boolean updateOffset(CoordinatorLayout parent, View child, View dependency) {
             final CoordinatorLayout.Behavior behavior =
                     ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
             if (behavior instanceof Behavior) {
                 // Offset the child so that it is below the app-bar (with any overlap)
-
-                final int appBarOffset = ((Behavior) behavior)
-                        .getTopBottomOffsetForScrollingSibling();
-                final int expandedMax = dependency.getHeight() - mOverlayTop;
-                final int collapsedMin = parent.getHeight() - child.getHeight();
-
-                if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
-                    // If we have an overlap top, and the dependency is an AppBarLayout, we control
-                    // the offset ourselves based on the appbar's scroll progress. This is so that
-                    // the scroll happens sequentially rather than linearly
-                    final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange();
-                    setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin,
-                            Math.abs(appBarOffset) / (float) scrollRange));
-                } else {
-                    setTopAndBottomOffset(dependency.getHeight() - mOverlayTop + appBarOffset);
-                }
+                final int offset = ((Behavior) behavior).getTopBottomOffsetForScrollingSibling();
+                setTopAndBottomOffset(dependency.getHeight() + offset
+                        - getOverlapForOffset(dependency, offset));
+                return true;
             }
             return false;
         }
 
+        private int getOverlapForOffset(final View dependency, final int offset) {
+            if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
+                final AppBarLayout abl = (AppBarLayout) dependency;
+                final int totalScrollRange = abl.getTotalScrollRange();
+                final int preScrollDown = abl.getDownNestedPreScrollRange();
+
+                if (preScrollDown != 0 && (totalScrollRange + offset) <= preScrollDown) {
+                    // If we're in a pre-scroll down. Don't use the offset at all.
+                    return 0;
+                } else {
+                    final int availScrollRange = totalScrollRange - preScrollDown;
+                    if (availScrollRange != 0) {
+                        // Else we'll use a interpolated ratio of the overlap, depending on offset
+                        final float percScrolled = offset / (float) availScrollRange;
+                        return MathUtils.constrain(
+                                Math.round((1f + percScrolled) * mOverlayTop), 0, mOverlayTop);
+                    }
+                }
+            }
+            return mOverlayTop;
+        }
+
         /**
          * Set the distance that this view should overlap any {@link AppBarLayout}.
          *
@@ -1287,14 +1239,24 @@
             return mOverlayTop;
         }
 
-        private static AppBarLayout findFirstAppBarLayout(List<View> views) {
+        @Override
+        View findFirstDependency(List<View> views) {
             for (int i = 0, z = views.size(); i < z; i++) {
                 View view = views.get(i);
                 if (view instanceof AppBarLayout) {
-                    return (AppBarLayout) view;
+                    return view;
                 }
             }
             return null;
         }
+
+        @Override
+        int getScrollRange(View v) {
+            if (v instanceof AppBarLayout) {
+                return ((AppBarLayout) v).getTotalScrollRange();
+            } else {
+                return super.getScrollRange(v);
+            }
+        }
     }
 }
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
new file mode 100644
index 0000000..cd24414
--- /dev/null
+++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
@@ -0,0 +1,417 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.IntDef;
+import android.support.design.R;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ViewDragHelper;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+
+
+/**
+ * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
+ * a bottom sheet.
+ */
+public class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
+
+    /**
+     * The bottom sheet is dragging.
+     */
+    public static final int STATE_DRAGGING = 1;
+
+    /**
+     * The bottom sheet is settling.
+     */
+    public static final int STATE_SETTLING = 2;
+
+    /**
+     * The bottom sheet is expanded.
+     */
+    public static final int STATE_EXPANDED = 3;
+
+    /**
+     * The bottom sheet is collapsed.
+     */
+    public static final int STATE_COLLAPSED = 4;
+
+    /** @hide */
+    @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    private int mPeekHeight;
+
+    private int mMinOffset;
+
+    private int mMaxOffset;
+
+    @State
+    private int mState = STATE_COLLAPSED;
+
+    private ViewDragHelper mViewDragHelper;
+
+    private boolean mIgnoreEvents;
+
+    private int mLastNestedScrollDy;
+
+    private int mParentHeight;
+
+    private WeakReference<V> mViewRef;
+
+    /**
+     * Default constructor for instantiating BottomSheetBehaviors.
+     */
+    public BottomSheetBehavior() {
+    }
+
+    /**
+     * Default constructor for inflating BottomSheetBehaviors from layout.
+     *
+     * @param context The {@link Context}.
+     * @param attrs   The {@link AttributeSet}.
+     */
+    public BottomSheetBehavior(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.BottomSheetBehavior_Params);
+        setPeekHeight(a.getDimensionPixelSize(
+                R.styleable.BottomSheetBehavior_Params_behavior_peekHeight, 0));
+        a.recycle();
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
+        return new SavedState(super.onSaveInstanceState(parent, child), mState);
+    }
+
+    @Override
+    public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(parent, child, ss.getSuperState());
+        mState = ss.state;
+        // Intermediate states are restored as collapsed state
+        if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
+            mState = STATE_COLLAPSED;
+        }
+    }
+
+    @Override
+    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
+        // First let the parent lay it out
+        parent.onLayoutChild(child, layoutDirection);
+        // Offset the bottom sheet
+        mParentHeight = parent.getHeight();
+        mMinOffset = Math.max(0, mParentHeight - child.getHeight());
+        mMaxOffset = mParentHeight - mPeekHeight;
+        if (mState == STATE_EXPANDED) {
+            ViewCompat.offsetTopAndBottom(child, mMinOffset);
+        } else {
+            ViewCompat.offsetTopAndBottom(child, mMaxOffset);
+            mState = STATE_COLLAPSED;
+        }
+        if (mViewDragHelper == null) {
+            mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
+        }
+        mViewRef = new WeakReference<>(child);
+        return true;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
+        int action = MotionEventCompat.getActionMasked(event);
+        switch (action) {
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                // Reset the ignore flag
+                if (mIgnoreEvents) {
+                    mIgnoreEvents = false;
+                    return false;
+                }
+                break;
+            case MotionEvent.ACTION_DOWN:
+                mIgnoreEvents = !parent.isPointInChildBounds(child,
+                        (int) event.getX(), (int) event.getY());
+                break;
+        }
+        return !mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event);
+    }
+
+    @Override
+    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
+        mViewDragHelper.processTouchEvent(event);
+        return true;
+    }
+
+    @Override
+    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child,
+            View directTargetChild, View target, int nestedScrollAxes) {
+        mLastNestedScrollDy = 0;
+        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
+    }
+
+    @Override
+    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
+            int dy, int[] consumed) {
+        int currentTop = child.getTop();
+        int newTop = currentTop - dy;
+        if (dy > 0) { // Scrolling up
+            if (newTop < mMinOffset) {
+                consumed[1] = currentTop - mMinOffset;
+                child.offsetTopAndBottom(-consumed[1]);
+                setStateInternal(STATE_EXPANDED);
+            } else {
+                consumed[1] = dy;
+                child.offsetTopAndBottom(-dy);
+                setStateInternal(STATE_DRAGGING);
+            }
+        } else if (dy < 0) { // Scrolling down
+            if (!ViewCompat.canScrollVertically(target, -1)) {
+                if (newTop > mMaxOffset) {
+                    consumed[1] = currentTop - mMaxOffset;
+                    child.offsetTopAndBottom(-consumed[1]);
+                    setStateInternal(STATE_COLLAPSED);
+                } else {
+                    consumed[1] = dy;
+                    child.offsetTopAndBottom(-dy);
+                    setStateInternal(STATE_DRAGGING);
+                }
+            }
+        }
+        mLastNestedScrollDy = dy;
+    }
+
+    @Override
+    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
+        if (mLastNestedScrollDy == 0 || child.getTop() == mMinOffset) {
+            return;
+        }
+        int top;
+        int targetState;
+        if (mLastNestedScrollDy > 0) {
+            top = mMinOffset;
+            targetState = STATE_EXPANDED;
+        } else {
+            top = mMaxOffset;
+            targetState = STATE_COLLAPSED;
+        }
+        setStateInternal(STATE_SETTLING);
+        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
+            ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
+        }
+    }
+
+    /**
+     * Sets the height of the bottom sheet when it is collapsed.
+     *
+     * @param peekHeight The height of the collapsed bottom sheet in pixels.
+     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
+     */
+    public final void setPeekHeight(int peekHeight) {
+        mPeekHeight = Math.max(0, peekHeight);
+        mMaxOffset = mParentHeight - peekHeight;
+    }
+
+    /**
+     * Gets the height of the bottom sheet when it is collapsed.
+     *
+     * @return The height of the collapsed bottom sheet.
+     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
+     */
+    public final int getPeekHeight() {
+        return mPeekHeight;
+    }
+
+    /**
+     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
+     * animation.
+     *
+     * @param state Either {@link #STATE_COLLAPSED} or {@link #STATE_EXPANDED}.
+     */
+    public final void setState(@State int state) {
+        V child = mViewRef.get();
+        if (child == null) {
+            return;
+        }
+        int top;
+        if (state == STATE_COLLAPSED) {
+            top = mMaxOffset;
+        } else if (state == STATE_EXPANDED) {
+            top = mMinOffset;
+        } else {
+            throw new IllegalArgumentException("Illegal state argument: " + state);
+        }
+        setStateInternal(STATE_SETTLING);
+        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
+            ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
+        }
+    }
+
+    /**
+     * Gets the current state of the bottom sheet.
+     *
+     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
+     * and {@link #STATE_SETTLING}.
+     */
+    @State
+    public final int getState() {
+        return mState;
+    }
+
+    private void setStateInternal(@State int state) {
+        if (mState == state) {
+            return;
+        }
+        mState = state;
+        // TODO: Invoke listeners.
+    }
+
+    private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
+
+        @Override
+        public boolean tryCaptureView(View child, int pointerId) {
+            return true;
+        }
+
+        @Override
+        public void onViewDragStateChanged(int state) {
+            if (state == ViewDragHelper.STATE_DRAGGING) {
+                setStateInternal(STATE_DRAGGING);
+            }
+        }
+
+        @Override
+        public void onViewReleased(View releasedChild, float xvel, float yvel) {
+            int top;
+            @State int targetState;
+            if (yvel < 0) {
+                top = mMinOffset;
+                targetState = STATE_EXPANDED;
+            } else {
+                top = mMaxOffset;
+                targetState = STATE_COLLAPSED;
+            }
+            setStateInternal(STATE_SETTLING);
+            if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
+                ViewCompat.postOnAnimation(releasedChild,
+                        new SettleRunnable(releasedChild, targetState));
+            }
+        }
+
+        @Override
+        public int clampViewPositionVertical(View child, int top, int dy) {
+            return MathUtils.constrain(top, mMinOffset, mMaxOffset);
+        }
+
+        @Override
+        public int clampViewPositionHorizontal(View child, int left, int dx) {
+            return child.getLeft();
+        }
+    };
+
+    private class SettleRunnable implements Runnable {
+
+        private final View mView;
+
+        @State
+        private final int mTargetState;
+
+        SettleRunnable(View view, @State int targetState) {
+            mView = view;
+            mTargetState = targetState;
+        }
+
+        @Override
+        public void run() {
+            if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
+                ViewCompat.postOnAnimation(mView, this);
+            } else {
+                setStateInternal(mTargetState);
+            }
+        }
+    }
+
+    protected static class SavedState extends View.BaseSavedState {
+
+        @State
+        final int state;
+
+        public SavedState(Parcel source) {
+            super(source);
+            //noinspection ResourceType
+            state = source.readInt();
+        }
+
+        public SavedState(Parcelable superState, @State int state) {
+            super(superState);
+            this.state = state;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(state);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+                    @Override
+                    public SavedState createFromParcel(Parcel source) {
+                        return new SavedState(source);
+                    }
+
+                    @Override
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
+    }
+
+    /*
+     * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.
+     *
+     * @param view The {@link View} with {@link BottomSheetBehavior}.
+     * @return The {@link BottomSheetBehavior} associated with the {@code view}.
+     */
+    @SuppressWarnings("unchecked")
+    public static <V extends View> BottomSheetBehavior<V> from(V view) {
+        ViewGroup.LayoutParams params = view.getLayoutParams();
+        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
+            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
+        }
+        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
+                .getBehavior();
+        if (!(behavior instanceof BottomSheetBehavior)) {
+            throw new IllegalArgumentException(
+                    "The view is not associated with BottomSheetBehavior");
+        }
+        return (BottomSheetBehavior<V>) behavior;
+    }
+
+}
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 082c316..9a38c7d 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -72,6 +72,9 @@
     private float mCollapsedDrawX;
     private float mCurrentDrawX;
     private float mCurrentDrawY;
+    private Typeface mCollapsedTypeface;
+    private Typeface mExpandedTypeface;
+    private Typeface mCurrentTypeface;
 
     private CharSequence mText;
     private CharSequence mTextToDraw;
@@ -93,6 +96,12 @@
     private Interpolator mPositionInterpolator;
     private Interpolator mTextSizeInterpolator;
 
+    private float mCollapsedShadowRadius, mCollapsedShadowDx, mCollapsedShadowDy;
+    private int mCollapsedShadowColor;
+
+    private float mExpandedShadowRadius, mExpandedShadowDx, mExpandedShadowDy;
+    private int mExpandedShadowColor;
+
     public CollapsingTextHelper(View view) {
         mView = view;
 
@@ -195,8 +204,16 @@
             mCollapsedTextSize = a.getDimensionPixelSize(
                     R.styleable.TextAppearance_android_textSize, (int) mCollapsedTextSize);
         }
+        mCollapsedShadowColor = a.getInt(R.styleable.TextAppearance_android_shadowColor, 0);
+        mCollapsedShadowDx = a.getFloat(R.styleable.TextAppearance_android_shadowDx, 0);
+        mCollapsedShadowDy = a.getFloat(R.styleable.TextAppearance_android_shadowDy, 0);
+        mCollapsedShadowRadius = a.getFloat(R.styleable.TextAppearance_android_shadowRadius, 0);
         a.recycle();
 
+        if (Build.VERSION.SDK_INT >= 16) {
+            mCollapsedTypeface = readFontFamilyTypeface(resId);
+        }
+
         recalculate();
     }
 
@@ -210,23 +227,58 @@
             mExpandedTextSize = a.getDimensionPixelSize(
                     R.styleable.TextAppearance_android_textSize, (int) mExpandedTextSize);
         }
+        mExpandedShadowColor = a.getInt(R.styleable.TextAppearance_android_shadowColor, 0);
+        mExpandedShadowDx = a.getFloat(R.styleable.TextAppearance_android_shadowDx, 0);
+        mExpandedShadowDy = a.getFloat(R.styleable.TextAppearance_android_shadowDy, 0);
+        mExpandedShadowRadius = a.getFloat(R.styleable.TextAppearance_android_shadowRadius, 0);
         a.recycle();
 
+        if (Build.VERSION.SDK_INT >= 16) {
+            mExpandedTypeface = readFontFamilyTypeface(resId);
+        }
+
         recalculate();
     }
 
-    void setTypeface(Typeface typeface) {
-        if (typeface == null) {
-            typeface = Typeface.DEFAULT;
+    private Typeface readFontFamilyTypeface(int resId) {
+        final TypedArray a = mView.getContext().obtainStyledAttributes(resId,
+                new int[]{android.R.attr.fontFamily});
+        try {
+            final String family = a.getString(0);
+            if (family != null) {
+                return Typeface.create(family, Typeface.NORMAL);
+            }
+        } finally {
+            a.recycle();
         }
-        if (mTextPaint.getTypeface() != typeface) {
-            mTextPaint.setTypeface(typeface);
+        return null;
+    }
+
+    void setCollapsedTypeface(Typeface typeface) {
+        if (mCollapsedTypeface != typeface) {
+            mCollapsedTypeface = typeface;
             recalculate();
         }
     }
 
-    Typeface getTypeface() {
-        return mTextPaint.getTypeface();
+    void setExpandedTypeface(Typeface typeface) {
+        if (mExpandedTypeface != typeface) {
+            mExpandedTypeface = typeface;
+            recalculate();
+        }
+    }
+
+    void setTypefaces(Typeface typeface) {
+        mCollapsedTypeface = mExpandedTypeface = typeface;
+        recalculate();
+    }
+
+    Typeface getCollapsedTypeface() {
+        return mCollapsedTypeface != null ? mCollapsedTypeface : Typeface.DEFAULT;
+    }
+
+    Typeface getExpandedTypeface() {
+        return mExpandedTypeface != null ? mExpandedTypeface : Typeface.DEFAULT;
     }
 
     /**
@@ -258,8 +310,10 @@
     }
 
     private void calculateCurrentOffsets() {
-        final float fraction = mExpandedFraction;
+        calculateOffsets(mExpandedFraction);
+    }
 
+    private void calculateOffsets(final float fraction) {
         interpolateBounds(fraction);
         mCurrentDrawX = lerp(mExpandedDrawX, mCollapsedDrawX, fraction,
                 mPositionInterpolator);
@@ -277,12 +331,20 @@
             mTextPaint.setColor(mCollapsedTextColor);
         }
 
+        mTextPaint.setShadowLayer(
+                lerp(mExpandedShadowRadius, mCollapsedShadowRadius, fraction, null),
+                lerp(mExpandedShadowDx, mCollapsedShadowDx, fraction, null),
+                lerp(mExpandedShadowDy, mCollapsedShadowDy, fraction, null),
+                blendColors(mExpandedShadowColor, mCollapsedShadowColor, fraction));
+
         ViewCompat.postInvalidateOnAnimation(mView);
     }
 
     private void calculateBaseOffsets() {
+        final float currentTextSize = mCurrentTextSize;
+
         // We then calculate the collapsed text size, using the same logic
-        mTextPaint.setTextSize(mCollapsedTextSize);
+        calculateUsingTextSize(mCollapsedTextSize);
         float width = mTextToDraw != null ?
                 mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0;
         final int collapsedAbsGravity = GravityCompat.getAbsoluteGravity(mCollapsedTextGravity,
@@ -314,7 +376,7 @@
                 break;
         }
 
-        mTextPaint.setTextSize(mExpandedTextSize);
+        calculateUsingTextSize(mExpandedTextSize);
         width = mTextToDraw != null
                 ? mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0;
         final int expandedAbsGravity = GravityCompat.getAbsoluteGravity(mExpandedTextGravity,
@@ -348,6 +410,8 @@
 
         // The bounds have changed so we need to clear the texture
         clearTexture();
+        // Now reset the text size back to the original
+        setInterpolatedTextSize(currentTextSize);
     }
 
     private void interpolateBounds(float fraction) {
@@ -417,47 +481,8 @@
                 : TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR).isRtl(text, 0, text.length());
     }
 
-    private void setInterpolatedTextSize(final float textSize) {
-        if (mText == null) return;
-
-        final float availableWidth;
-        final float newTextSize;
-        boolean updateDrawText = false;
-
-        if (isClose(textSize, mCollapsedTextSize)) {
-            availableWidth = mCollapsedBounds.width();
-            newTextSize = mCollapsedTextSize;
-            mScale = 1f;
-        } else {
-            availableWidth = mExpandedBounds.width();
-            newTextSize = mExpandedTextSize;
-
-            if (isClose(textSize, mExpandedTextSize)) {
-                // If we're close to the expanded text size, snap to it and use a scale of 1
-                mScale = 1f;
-            } else {
-                // Else, we'll scale down from the expanded text size
-                mScale = textSize / mExpandedTextSize;
-            }
-        }
-
-        if (availableWidth > 0) {
-            updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged;
-            mCurrentTextSize = newTextSize;
-            mBoundsChanged = false;
-        }
-
-        if (mTextToDraw == null || updateDrawText) {
-            mTextPaint.setTextSize(mCurrentTextSize);
-
-            // If we don't currently have text to draw, or the text size has changed, ellipsize...
-            final CharSequence title = TextUtils.ellipsize(mText, mTextPaint,
-                    availableWidth, TextUtils.TruncateAt.END);
-            if (mTextToDraw == null || !mTextToDraw.equals(title)) {
-                mTextToDraw = title;
-            }
-            mIsRtl = calculateIsRtl(mTextToDraw);
-        }
+    private void setInterpolatedTextSize(float textSize) {
+        calculateUsingTextSize(textSize);
 
         // Use our texture if the scale isn't 1.0
         mUseTexture = USE_SCALING_TEXTURE && mScale != 1f;
@@ -470,21 +495,72 @@
         ViewCompat.postInvalidateOnAnimation(mView);
     }
 
+    private void calculateUsingTextSize(final float textSize) {
+        if (mText == null) return;
+
+        final float availableWidth;
+        final float newTextSize;
+        boolean updateDrawText = false;
+
+        if (isClose(textSize, mCollapsedTextSize)) {
+            availableWidth = mCollapsedBounds.width();
+            newTextSize = mCollapsedTextSize;
+            mScale = 1f;
+            if (mCurrentTypeface != mCollapsedTypeface) {
+                mCurrentTypeface = mCollapsedTypeface;
+                updateDrawText = true;
+            }
+        } else {
+            availableWidth = mExpandedBounds.width();
+            newTextSize = mExpandedTextSize;
+            if (mCurrentTypeface != mExpandedTypeface) {
+                mCurrentTypeface = mExpandedTypeface;
+                updateDrawText = true;
+            }
+
+            if (isClose(textSize, mExpandedTextSize)) {
+                // If we're close to the expanded text size, snap to it and use a scale of 1
+                mScale = 1f;
+            } else {
+                // Else, we'll scale down from the expanded text size
+                mScale = textSize / mExpandedTextSize;
+            }
+        }
+
+        if (availableWidth > 0) {
+            updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged || updateDrawText;
+            mCurrentTextSize = newTextSize;
+            mBoundsChanged = false;
+        }
+
+        if (mTextToDraw == null || updateDrawText) {
+            mTextPaint.setTextSize(mCurrentTextSize);
+            mTextPaint.setTypeface(mCurrentTypeface);
+
+            // If we don't currently have text to draw, or the text size has changed, ellipsize...
+            final CharSequence title = TextUtils.ellipsize(mText, mTextPaint,
+                    availableWidth, TextUtils.TruncateAt.END);
+            if (!TextUtils.equals(title, mTextToDraw)) {
+                mTextToDraw = title;
+                mIsRtl = calculateIsRtl(mTextToDraw);
+            }
+        }
+    }
+
     private void ensureExpandedTexture() {
         if (mExpandedTitleTexture != null || mExpandedBounds.isEmpty()
                 || TextUtils.isEmpty(mTextToDraw)) {
             return;
         }
 
-        mTextPaint.setTextSize(mExpandedTextSize);
-        mTextPaint.setColor(mExpandedTextColor);
+        calculateOffsets(0f);
         mTextureAscent = mTextPaint.ascent();
         mTextureDescent = mTextPaint.descent();
 
         final int w = Math.round(mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()));
         final int h = Math.round(mTextureDescent - mTextureAscent);
 
-        if (w <= 0 && h <= 0) {
+        if (w <= 0 || h <= 0) {
             return; // If the width or height are 0, return
         }
 
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
index 230a1d0..62fef07 100644
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
@@ -20,12 +20,14 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.annotation.ColorInt;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.StyleRes;
 import android.support.design.R;
@@ -94,14 +96,15 @@
     private Toolbar mToolbar;
     private View mDummyView;
 
-    private int mExpandedMarginLeft;
+    private int mExpandedMarginStart;
     private int mExpandedMarginTop;
-    private int mExpandedMarginRight;
+    private int mExpandedMarginEnd;
     private int mExpandedMarginBottom;
 
     private final Rect mTmpRect = new Rect();
     private final CollapsingTextHelper mCollapsingTextHelper;
     private boolean mCollapsingTitleEnabled;
+    private boolean mDrawCollapsingTitle;
 
     private Drawable mContentScrim;
     private Drawable mStatusBarScrim;
@@ -126,6 +129,8 @@
     public CollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        ThemeUtils.checkAppCompatTheme(context);
+
         mCollapsingTextHelper = new CollapsingTextHelper(this);
         mCollapsingTextHelper.setTextSizeInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
 
@@ -140,28 +145,16 @@
                 a.getInt(R.styleable.CollapsingToolbarLayout_collapsedTitleGravity,
                         GravityCompat.START | Gravity.CENTER_VERTICAL));
 
-        mExpandedMarginLeft = mExpandedMarginTop = mExpandedMarginRight = mExpandedMarginBottom =
+        mExpandedMarginStart = mExpandedMarginTop = mExpandedMarginEnd = mExpandedMarginBottom =
                 a.getDimensionPixelSize(R.styleable.CollapsingToolbarLayout_expandedTitleMargin, 0);
 
-        final boolean isRtl = ViewCompat.getLayoutDirection(this)
-                == ViewCompat.LAYOUT_DIRECTION_RTL;
         if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginStart)) {
-            final int marginStart = a.getDimensionPixelSize(
+            mExpandedMarginStart = a.getDimensionPixelSize(
                     R.styleable.CollapsingToolbarLayout_expandedTitleMarginStart, 0);
-            if (isRtl) {
-                mExpandedMarginRight = marginStart;
-            } else {
-                mExpandedMarginLeft = marginStart;
-            }
         }
         if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginEnd)) {
-            final int marginEnd = a.getDimensionPixelSize(
+            mExpandedMarginEnd = a.getDimensionPixelSize(
                     R.styleable.CollapsingToolbarLayout_expandedTitleMarginEnd, 0);
-            if (isRtl) {
-                mExpandedMarginLeft = marginEnd;
-            } else {
-                mExpandedMarginRight = marginEnd;
-            }
         }
         if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginTop)) {
             mExpandedMarginTop = a.getDimensionPixelSize(
@@ -192,7 +185,6 @@
             mCollapsingTextHelper.setCollapsedTextAppearance(
                     a.getResourceId(
                             R.styleable.CollapsingToolbarLayout_collapsedTitleTextAppearance, 0));
-
         }
 
         setContentScrim(a.getDrawable(R.styleable.CollapsingToolbarLayout_contentScrim));
@@ -254,7 +246,7 @@
         }
 
         // Let the collapsing text helper draw it's text
-        if (mCollapsingTitleEnabled) {
+        if (mCollapsingTitleEnabled && mDrawCollapsingTitle) {
             mCollapsingTextHelper.draw(canvas);
         }
 
@@ -360,6 +352,31 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
+        // Update the collapsed bounds by getting it's transformed bounds. This needs to be done
+        // before the children are offset below
+        if (mCollapsingTitleEnabled && mDummyView != null) {
+            // We only draw the title if the dummy view is being displayed (Toolbar removes
+            // views if there is no space)
+            mDrawCollapsingTitle = mDummyView.isShown();
+
+            if (mDrawCollapsingTitle) {
+                ViewGroupUtils.getDescendantRect(this, mDummyView, mTmpRect);
+                mCollapsingTextHelper.setCollapsedBounds(mTmpRect.left, bottom - mTmpRect.height(),
+                        mTmpRect.right, bottom);
+
+                final boolean isRtl = ViewCompat.getLayoutDirection(this)
+                        == ViewCompat.LAYOUT_DIRECTION_RTL;
+                // Update the expanded bounds
+                mCollapsingTextHelper.setExpandedBounds(
+                        isRtl ? mExpandedMarginEnd : mExpandedMarginStart,
+                        mTmpRect.bottom + mExpandedMarginTop,
+                        right - left - (isRtl ? mExpandedMarginStart : mExpandedMarginEnd),
+                        bottom - top - mExpandedMarginBottom);
+                // Now recalculate using the new bounds
+                mCollapsingTextHelper.recalculate();
+            }
+        }
+
         // Update our child view offset helpers
         for (int i = 0, z = getChildCount(); i < z; i++) {
             final View child = getChildAt(i);
@@ -376,21 +393,6 @@
             getViewOffsetHelper(child).onViewLayout();
         }
 
-        // Update the collapsed bounds by getting it's transformed bounds
-        if (mCollapsingTitleEnabled && mDummyView != null) {
-            ViewGroupUtils.getDescendantRect(this, mDummyView, mTmpRect);
-            mCollapsingTextHelper.setCollapsedBounds(mTmpRect.left, bottom - mTmpRect.height(),
-                    mTmpRect.right, bottom);
-            // Update the expanded bounds
-            mCollapsingTextHelper.setExpandedBounds(
-                    mExpandedMarginLeft,
-                    mTmpRect.bottom + mExpandedMarginTop,
-                    right - left - mExpandedMarginRight,
-                    bottom - top - mExpandedMarginBottom);
-
-            mCollapsingTextHelper.recalculate();
-        }
-
         // Finally, set our minimum height to enable proper AppBarLayout collapsing
         if (mToolbar != null) {
             if (mCollapsingTitleEnabled && TextUtils.isEmpty(mCollapsingTextHelper.getText())) {
@@ -462,25 +464,38 @@
         return mCollapsingTitleEnabled;
     }
 
-    private void showScrim() {
-        if (!mScrimsAreShown) {
-            if (ViewCompat.isLaidOut(this) && !isInEditMode()) {
-                animateScrim(255);
-            } else {
-                setScrimAlpha(255);
-            }
-            mScrimsAreShown = true;
-        }
+    /**
+     * Set whether the content scrim and/or status bar scrim should be shown or not. Any change
+     * in the vertical scroll may overwrite this value. Any visibility change will be animated if
+     * this view has already been laid out.
+     *
+     * @param shown whether the scrims should be shown
+     *
+     * @see #getStatusBarScrim()
+     * @see #getContentScrim()
+     */
+    public void setScrimsShown(boolean shown) {
+        setScrimsShown(shown, ViewCompat.isLaidOut(this) && !isInEditMode());
     }
 
-    private void hideScrim() {
-        if (mScrimsAreShown) {
-            if (ViewCompat.isLaidOut(this) && !isInEditMode()) {
-                animateScrim(0);
+    /**
+     * Set whether the content scrim and/or status bar scrim should be shown or not. Any change
+     * in the vertical scroll may overwrite this value.
+     *
+     * @param shown whether the scrims should be shown
+     * @param animate whether to animate the visibility change
+     *
+     * @see #getStatusBarScrim()
+     * @see #getContentScrim()
+     */
+    public void setScrimsShown(boolean shown, boolean animate) {
+        if (mScrimsAreShown != shown) {
+            if (animate) {
+                animateScrim(shown ? 0xFF : 0x0);
             } else {
-                setScrimAlpha(0);
+                setScrimAlpha(shown ? 0xFF : 0x0);
             }
-            mScrimsAreShown = false;
+            mScrimsAreShown = shown;
         }
     }
 
@@ -489,7 +504,10 @@
         if (mScrimAnimator == null) {
             mScrimAnimator = ViewUtils.createAnimator();
             mScrimAnimator.setDuration(SCRIM_ANIMATION_DURATION);
-            mScrimAnimator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+            mScrimAnimator.setInterpolator(
+                    targetAlpha > mScrimAlpha
+                            ? AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR
+                            : AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
             mScrimAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
                 @Override
                 public void onAnimationUpdate(ValueAnimatorCompat animator) {
@@ -529,11 +547,14 @@
             if (mContentScrim != null) {
                 mContentScrim.setCallback(null);
             }
-
-            mContentScrim = drawable;
-            drawable.setBounds(0, 0, getWidth(), getHeight());
-            drawable.setCallback(this);
-            drawable.mutate().setAlpha(mScrimAlpha);
+            if (drawable != null) {
+                mContentScrim = drawable.mutate();
+                drawable.setBounds(0, 0, getWidth(), getHeight());
+                drawable.setCallback(this);
+                drawable.setAlpha(mScrimAlpha);
+            } else {
+                mContentScrim = null;
+            }
             ViewCompat.postInvalidateOnAnimation(this);
         }
     }
@@ -660,7 +681,7 @@
      * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_collapsedTitleGravity
      */
     public void setCollapsedTitleGravity(int gravity) {
-        mCollapsingTextHelper.setExpandedTextGravity(gravity);
+        mCollapsingTextHelper.setCollapsedTextGravity(gravity);
     }
 
     /**
@@ -712,6 +733,147 @@
     }
 
     /**
+     * Set the typeface to use for the collapsed title.
+     *
+     * @param typeface typeface to use, or {@code null} to use the default.
+     */
+    public void setCollapsedTitleTypeface(@Nullable Typeface typeface) {
+        mCollapsingTextHelper.setCollapsedTypeface(typeface);
+    }
+
+    /**
+     * Returns the typeface used for the collapsed title.
+     */
+    @NonNull
+    public Typeface getCollapsedTitleTypeface() {
+        return mCollapsingTextHelper.getCollapsedTypeface();
+    }
+
+    /**
+     * Set the typeface to use for the expanded title.
+     *
+     * @param typeface typeface to use, or {@code null} to use the default.
+     */
+    public void setExpandedTitleTypeface(@Nullable Typeface typeface) {
+        mCollapsingTextHelper.setExpandedTypeface(typeface);
+    }
+
+    /**
+     * Returns the typeface used for the expanded title.
+     */
+    @NonNull
+    public Typeface getExpandedTitleTypeface() {
+        return mCollapsingTextHelper.getExpandedTypeface();
+    }
+
+    /**
+     * Sets the expanded title margins.
+     *
+     * @param start the starting title margin in pixels
+     * @param top the top title margin in pixels
+     * @param end the ending title margin in pixels
+     * @param bottom the bottom title margin in pixels
+     *
+     * @see #getExpandedTitleMarginStart()
+     * @see #getExpandedTitleMarginTop()
+     * @see #getExpandedTitleMarginEnd()
+     * @see #getExpandedTitleMarginBottom()
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMargin
+     */
+    public void setExpandedTitleMargin(int start, int top, int end, int bottom) {
+        mExpandedMarginStart = start;
+        mExpandedMarginTop = top;
+        mExpandedMarginEnd = end;
+        mExpandedMarginBottom = bottom;
+        requestLayout();
+    }
+
+    /**
+     * @return the starting expanded title margin in pixels
+     *
+     * @see #setExpandedTitleMarginStart(int)
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginStart
+     */
+    public int getExpandedTitleMarginStart() {
+        return mExpandedMarginStart;
+    }
+
+    /**
+     * Sets the starting expanded title margin in pixels.
+     *
+     * @param margin the starting title margin in pixels
+     * @see #getExpandedTitleMarginStart()
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginStart
+     */
+    public void setExpandedTitleMarginStart(int margin) {
+        mExpandedMarginStart = margin;
+        requestLayout();
+    }
+
+    /**
+     * @return the top expanded title margin in pixels
+     * @see #setExpandedTitleMarginTop(int)
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginTop
+     */
+    public int getExpandedTitleMarginTop() {
+        return mExpandedMarginTop;
+    }
+
+    /**
+     * Sets the top expanded title margin in pixels.
+     *
+     * @param margin the top title margin in pixels
+     * @see #getExpandedTitleMarginTop()
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginTop
+     */
+    public void setExpandedTitleMarginTop(int margin) {
+        mExpandedMarginTop = margin;
+        requestLayout();
+    }
+
+    /**
+     * @return the ending expanded title margin in pixels
+     * @see #setExpandedTitleMarginEnd(int)
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginEnd
+     */
+    public int getExpandedTitleMarginEnd() {
+        return mExpandedMarginEnd;
+    }
+
+    /**
+     * Sets the ending expanded title margin in pixels.
+     *
+     * @param margin the ending title margin in pixels
+     * @see #getExpandedTitleMarginEnd()
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginEnd
+     */
+    public void setExpandedTitleMarginEnd(int margin) {
+        mExpandedMarginEnd = margin;
+        requestLayout();
+    }
+
+    /**
+     * @return the bottom expanded title margin in pixels
+     * @see #setExpandedTitleMarginBottom(int)
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginBottom
+     */
+    public int getExpandedTitleMarginBottom() {
+        return mExpandedMarginBottom;
+    }
+
+    /**
+     * Sets the bottom expanded title margin in pixels.
+     *
+     * @param margin the bottom title margin in pixels
+     * @see #getExpandedTitleMarginBottom()
+     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginBottom
+     */
+    public void setExpandedTitleMarginBottom(int margin) {
+        mExpandedMarginBottom = margin;
+        requestLayout();
+    }
+
+    /**
      * The additional offset used to define when to trigger the scrim visibility change.
      */
     final int getScrimTriggerOffset() {
@@ -878,11 +1040,7 @@
 
             // Show or hide the scrims if needed
             if (mContentScrim != null || mStatusBarScrim != null) {
-                if (getHeight() + verticalOffset < getScrimTriggerOffset() + insetTop) {
-                    showScrim();
-                } else {
-                    hideScrim();
-                }
+                setScrimsShown(getHeight() + verticalOffset < getScrimTriggerOffset() + insetTop);
             }
 
             if (mStatusBarScrim != null && insetTop > 0) {
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index 708a123..3d16ac9 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -31,6 +31,8 @@
 import android.os.SystemClock;
 import android.support.design.R;
 import android.support.v4.content.ContextCompat;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.NestedScrollingParent;
@@ -85,7 +87,12 @@
  */
 public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent {
     static final String TAG = "CoordinatorLayout";
-    static final String WIDGET_PACKAGE_NAME = CoordinatorLayout.class.getPackage().getName();
+    static final String WIDGET_PACKAGE_NAME;
+
+    static {
+        final Package pkg = CoordinatorLayout.class.getPackage();
+        WIDGET_PACKAGE_NAME = pkg != null ? pkg.getName() : null;
+    }
 
     private static final int TYPE_ON_INTERCEPT = 0;
     private static final int TYPE_ON_TOUCH = 1;
@@ -168,6 +175,8 @@
     public CoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        ThemeUtils.checkAppCompatTheme(context);
+
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CoordinatorLayout,
                 defStyleAttr, R.style.Widget_Design_CoordinatorLayout);
         final int keylineArrayRes = a.getResourceId(R.styleable.CoordinatorLayout_keylines, 0);
@@ -499,8 +508,10 @@
             // Fully qualified package name.
             fullName = name;
         } else {
-            // Assume stock behavior in this package.
-            fullName = WIDGET_PACKAGE_NAME + '.' + name;
+            // Assume stock behavior in this package (if we have one)
+            fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)
+                    ? (WIDGET_PACKAGE_NAME + '.' + name)
+                    : name;
         }
 
         try {
@@ -546,26 +557,18 @@
     }
 
     private void prepareChildren() {
-        final int childCount = getChildCount();
-
-        boolean resortRequired = mDependencySortedChildren.size() != childCount;
-
-        for (int i = 0; i < childCount; i++) {
+        mDependencySortedChildren.clear();
+        for (int i = 0, count = getChildCount(); i < count; i++) {
             final View child = getChildAt(i);
-            final LayoutParams lp = getResolvedLayoutParams(child);
-            if (!resortRequired && lp.isDirty(this, child)) {
-                resortRequired = true;
-            }
-            lp.findAnchorView(this, child);
-        }
 
-        if (resortRequired) {
-            mDependencySortedChildren.clear();
-            for (int i = 0; i < childCount; i++) {
-                mDependencySortedChildren.add(getChildAt(i));
-            }
-            Collections.sort(mDependencySortedChildren, mLayoutDependencyComparator);
+            final LayoutParams lp = getResolvedLayoutParams(child);
+            lp.findAnchorView(this, child);
+
+            mDependencySortedChildren.add(child);
         }
+        // We need to use a selection sort here to make sure that every item is compared
+        // against each other
+        selectionSort(mDependencySortedChildren, mLayoutDependencyComparator);
     }
 
     /**
@@ -1143,15 +1146,23 @@
         }
     }
 
-    void dispatchDependentViewRemoved(View removedChild) {
-        final int childCount = getChildCount();
+    void dispatchDependentViewRemoved(View view) {
+        final int childCount = mDependencySortedChildren.size();
+        boolean viewSeen = false;
         for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final Behavior b = lp.getBehavior();
-
-            if (b != null && b.layoutDependsOn(this, child, removedChild)) {
-                b.onDependentViewRemoved(this, child, removedChild);
+            final View child = mDependencySortedChildren.get(i);
+            if (child == view) {
+                // We've seen our view, which means that any Views after this could be dependent
+                viewSeen = true;
+                continue;
+            }
+            if (viewSeen) {
+                CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)
+                        child.getLayoutParams();
+                CoordinatorLayout.Behavior b = lp.getBehavior();
+                if (b != null && lp.dependsOn(this, child, view)) {
+                    b.onDependentViewRemoved(this, child, view);
+                }
             }
         }
     }
@@ -2246,10 +2257,6 @@
         /**
          * Get the id of this view's anchor.
          *
-         * <p>The view with this id must be a descendant of the CoordinatorLayout containing
-         * the child view this LayoutParams belongs to. It may not be the child view with
-         * this LayoutParams or a descendant of it.</p>
-         *
          * @return A {@link View#getId() view id} or {@link View#NO_ID} if there is no anchor
          */
         public int getAnchorId() {
@@ -2257,7 +2264,7 @@
         }
 
         /**
-         * Get the id of this view's anchor.
+         * Set the id of this view's anchor.
          *
          * <p>The view with this id must be a descendant of the CoordinatorLayout containing
          * the child view this LayoutParams belongs to. It may not be the child view with
@@ -2454,9 +2461,18 @@
          * Determine the anchor view for the child view this LayoutParams is assigned to.
          * Assumes mAnchorId is valid.
          */
-        private void resolveAnchorView(View forChild, CoordinatorLayout parent) {
+        private void resolveAnchorView(final View forChild, final CoordinatorLayout parent) {
             mAnchorView = parent.findViewById(mAnchorId);
             if (mAnchorView != null) {
+                if (mAnchorView == parent) {
+                    if (parent.isInEditMode()) {
+                        mAnchorView = mAnchorDirectChild = null;
+                        return;
+                    }
+                    throw new IllegalStateException(
+                            "View can not be anchored to the the parent CoordinatorLayout");
+                }
+
                 View directChild = mAnchorView;
                 for (ViewParent p = mAnchorView.getParent();
                         p != parent && p != null;
@@ -2586,7 +2602,7 @@
     protected static class SavedState extends BaseSavedState {
         SparseArray<Parcelable> behaviorStates;
 
-        public SavedState(Parcel source) {
+        public SavedState(Parcel source, ClassLoader loader) {
             super(source);
 
             final int size = source.readInt();
@@ -2594,8 +2610,7 @@
             final int[] ids = new int[size];
             source.readIntArray(ids);
 
-            final Parcelable[] states = source.readParcelableArray(
-                    CoordinatorLayout.class.getClassLoader());
+            final Parcelable[] states = source.readParcelableArray(loader);
 
             behaviorStates = new SparseArray<>(size);
             for (int i = 0; i < size; i++) {
@@ -2626,17 +2641,50 @@
 
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR =
-                new Parcelable.Creator<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel source) {
-                        return new SavedState(source);
-                    }
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
 
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                };
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        });
+    }
+
+    private static void selectionSort(final List<View> list, final Comparator<View> comparator) {
+        if (list == null || list.size() < 2) {
+            return;
+        }
+
+        final View[] array = new View[list.size()];
+        list.toArray(array);
+        final int count = array.length;
+
+        for (int i = 0; i < count; i++) {
+            int min = i;
+
+            for (int j = i + 1; j < count; j++) {
+                if (comparator.compare(array[j], array[min]) < 0) {
+                    min = j;
+                }
+            }
+
+            if (i != min) {
+                // We have a different min so swap the items
+                final View minItem = array[min];
+                array[min] = array[i];
+                array[i] = minItem;
+            }
+        }
+
+        // Finally add the array back into the collection
+        list.clear();
+        for (int i = 0; i < count; i++) {
+            list.add(array[i]);
+        }
     }
 }
diff --git a/design/src/android/support/design/widget/DrawableUtils.java b/design/src/android/support/design/widget/DrawableUtils.java
new file mode 100644
index 0000000..1c46e6b2
--- /dev/null
+++ b/design/src/android/support/design/widget/DrawableUtils.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.os.Build;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Caution. Gross hacks ahead.
+ */
+class DrawableUtils {
+
+    private static final String LOG_TAG = "DrawableUtils";
+
+    private static Method sSetConstantStateMethod;
+    private static boolean sSetConstantStateMethodFetched;
+
+    private static Field sDrawableContainerStateField;
+    private static boolean sDrawableContainerStateFieldFetched;
+
+    private DrawableUtils() {}
+
+    static boolean setContainerConstantState(DrawableContainer drawable,
+            Drawable.ConstantState constantState) {
+        if (Build.VERSION.SDK_INT >= 9) {
+            // We can use getDeclaredMethod() on v9+
+            return setContainerConstantStateV9(drawable, constantState);
+        } else {
+            // Else we'll just have to set the field directly
+            return setContainerConstantStateV7(drawable, constantState);
+        }
+    }
+
+    private static boolean setContainerConstantStateV9(DrawableContainer drawable,
+            Drawable.ConstantState constantState) {
+        if (!sSetConstantStateMethodFetched) {
+            try {
+                sSetConstantStateMethod = DrawableContainer.class.getDeclaredMethod(
+                        "setConstantState", DrawableContainer.DrawableContainerState.class);
+                sSetConstantStateMethod.setAccessible(true);
+            } catch (NoSuchMethodException e) {
+                Log.e(LOG_TAG, "Could not fetch setConstantState(). Oh well.");
+            }
+            sSetConstantStateMethodFetched = true;
+        }
+        if (sSetConstantStateMethod != null) {
+            try {
+                sSetConstantStateMethod.invoke(drawable, constantState);
+                return true;
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Could not invoke setConstantState(). Oh well.");
+            }
+        }
+        return false;
+    }
+
+    private static boolean setContainerConstantStateV7(DrawableContainer drawable,
+            Drawable.ConstantState constantState) {
+        if (!sDrawableContainerStateFieldFetched) {
+            try {
+                sDrawableContainerStateField = DrawableContainer.class
+                        .getDeclaredField("mDrawableContainerStateField");
+                sDrawableContainerStateField.setAccessible(true);
+            } catch (NoSuchFieldException e) {
+                Log.e(LOG_TAG, "Could not fetch mDrawableContainerStateField. Oh well.");
+            }
+            sDrawableContainerStateFieldFetched = true;
+        }
+        if (sDrawableContainerStateField != null) {
+            try {
+                sDrawableContainerStateField.set(drawable, constantState);
+                return true;
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Could not set mDrawableContainerStateField. Oh well.");
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 9a7b727..998fc2f 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -28,8 +28,10 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.design.R;
+import android.support.design.widget.FloatingActionButtonImpl.InternalVisibilityChangedListener;
 import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -53,7 +55,30 @@
  * @attr ref android.support.design.R.styleable#FloatingActionButton_fabSize
  */
 @CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
-public class FloatingActionButton extends ImageView {
+public class FloatingActionButton extends VisibilityAwareImageButton {
+
+    private static final String LOG_TAG = "FloatingActionButton";
+
+    /**
+     * Callback to be invoked when the visibility of a FloatingActionButton changes.
+     */
+    public abstract static class OnVisibilityChangedListener {
+        /**
+         * Called when a FloatingActionButton has been
+         * {@link #show(OnVisibilityChangedListener) shown}.
+         *
+         * @param fab the FloatingActionButton that was shown.
+         */
+        public void onShown(FloatingActionButton fab) {}
+
+        /**
+         * Called when a FloatingActionButton has been
+         * {@link #hide(OnVisibilityChangedListener) hidden}.
+         *
+         * @param fab the FloatingActionButton that was hidden.
+         */
+        public void onHidden(FloatingActionButton fab) {}
+    }
 
     // These values must match those in the attrs declaration
     private static final int SIZE_MINI = 1;
@@ -65,8 +90,9 @@
     private int mBorderWidth;
     private int mRippleColor;
     private int mSize;
-    private int mContentPadding;
+    private int mImagePadding;
 
+    private boolean mCompatPadding;
     private final Rect mShadowPadding;
 
     private final FloatingActionButtonImpl mImpl;
@@ -82,12 +108,13 @@
     public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        ThemeUtils.checkAppCompatTheme(context);
+
         mShadowPadding = new Rect();
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.FloatingActionButton, defStyleAttr,
                 R.style.Widget_Design_FloatingActionButton);
-        Drawable background = a.getDrawable(R.styleable.FloatingActionButton_android_background);
         mBackgroundTint = a.getColorStateList(R.styleable.FloatingActionButton_backgroundTint);
         mBackgroundTintMode = parseTintMode(a.getInt(
                 R.styleable.FloatingActionButton_backgroundTintMode, -1), null);
@@ -97,6 +124,7 @@
         final float elevation = a.getDimension(R.styleable.FloatingActionButton_elevation, 0f);
         final float pressedTranslationZ = a.getDimension(
                 R.styleable.FloatingActionButton_pressedTranslationZ, 0f);
+        mCompatPadding = a.getBoolean(R.styleable.FloatingActionButton_useCompatPadding, false);
         a.recycle();
 
         final ShadowViewDelegate delegate = new ShadowViewDelegate() {
@@ -108,36 +136,38 @@
             @Override
             public void setShadowPadding(int left, int top, int right, int bottom) {
                 mShadowPadding.set(left, top, right, bottom);
-
-                setPadding(left + mContentPadding, top + mContentPadding,
-                        right + mContentPadding, bottom + mContentPadding);
+                setPadding(left + mImagePadding, top + mImagePadding,
+                        right + mImagePadding, bottom + mImagePadding);
             }
 
             @Override
             public void setBackgroundDrawable(Drawable background) {
                 FloatingActionButton.super.setBackgroundDrawable(background);
             }
+
+            @Override
+            public boolean isCompatPaddingEnabled() {
+                return mCompatPadding;
+            }
         };
 
         final int sdk = Build.VERSION.SDK_INT;
         if (sdk >= 21) {
             mImpl = new FloatingActionButtonLollipop(this, delegate);
-        } else if (sdk >= 12) {
-            mImpl = new FloatingActionButtonHoneycombMr1(this, delegate);
+        } else if (sdk >= 14) {
+            mImpl = new FloatingActionButtonIcs(this, delegate);
         } else {
             mImpl = new FloatingActionButtonEclairMr1(this, delegate);
         }
 
-        final int maxContentSize = (int) getResources().getDimension(
-                R.dimen.design_fab_content_size);
-        mContentPadding = (getSizeDimension() - maxContentSize) / 2;
+        final int maxImageSize = (int) getResources().getDimension(R.dimen.design_fab_image_size);
+        mImagePadding = (getSizeDimension() - maxImageSize) / 2;
 
-        mImpl.setBackgroundDrawable(background, mBackgroundTint,
-                mBackgroundTintMode, mRippleColor, mBorderWidth);
+        mImpl.setBackgroundDrawable(mBackgroundTint, mBackgroundTintMode,
+                mRippleColor, mBorderWidth);
         mImpl.setElevation(elevation);
         mImpl.setPressedTranslationZ(pressedTranslationZ);
-
-        setClickable(true);
+        mImpl.updatePadding();
     }
 
     @Override
@@ -163,6 +193,8 @@
      * When running on devices with KitKat or below, we draw a fill rather than a ripple.
      *
      * @param color ARGB color to use for the ripple.
+     *
+     * @attr ref android.support.design.R.styleable#FloatingActionButton_rippleColor
      */
     public void setRippleColor(@ColorInt int color) {
         if (mRippleColor != color) {
@@ -196,7 +228,6 @@
         }
     }
 
-
     /**
      * Return the blending mode used to apply the tint to the background
      * drawable, if specified.
@@ -227,19 +258,40 @@
     }
 
     @Override
-    public void setBackgroundDrawable(@NonNull Drawable background) {
-        if (mImpl != null) {
-            mImpl.setBackgroundDrawable(
-                    background, mBackgroundTint, mBackgroundTintMode, mRippleColor, mBorderWidth);
-        }
+    public void setBackgroundDrawable(Drawable background) {
+        Log.i(LOG_TAG, "Setting a custom background is not supported.");
+    }
+
+    @Override
+    public void setBackgroundResource(int resid) {
+        Log.i(LOG_TAG, "Setting a custom background is not supported.");
+    }
+
+    @Override
+    public void setBackgroundColor(int color) {
+        Log.i(LOG_TAG, "Setting a custom background is not supported.");
     }
 
     /**
      * Shows the button.
-     * <p>This method will animate it the button show if the view has already been laid out.</p>
+     * <p>This method will animate the button show if the view has already been laid out.</p>
      */
     public void show() {
-        mImpl.show();
+        show(null);
+    }
+
+    /**
+     * Shows the button.
+     * <p>This method will animate the button show if the view has already been laid out.</p>
+     *
+     * @param listener the listener to notify when this view is shown
+     */
+    public void show(@Nullable final OnVisibilityChangedListener listener) {
+        show(listener, true);
+    }
+
+    private void show(OnVisibilityChangedListener listener, boolean fromUser) {
+        mImpl.show(wrapOnVisibilityChangedListener(listener), fromUser);
     }
 
     /**
@@ -247,7 +299,71 @@
      * <p>This method will animate the button hide if the view has already been laid out.</p>
      */
     public void hide() {
-        mImpl.hide();
+        hide(null);
+    }
+
+    /**
+     * Hides the button.
+     * <p>This method will animate the button hide if the view has already been laid out.</p>
+     *
+     * @param listener the listener to notify when this view is hidden
+     */
+    public void hide(@Nullable OnVisibilityChangedListener listener) {
+        hide(listener, true);
+    }
+
+    private void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
+        mImpl.hide(wrapOnVisibilityChangedListener(listener), fromUser);
+    }
+
+    /**
+     * Set whether FloatingActionButton should add inner padding on platforms Lollipop and after,
+     * to ensure consistent dimensions on all platforms.
+     *
+     * @param useCompatPadding true if FloatingActionButton is adding inner padding on platforms
+     *                         Lollipop and after, to ensure consistent dimensions on all platforms.
+     *
+     * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding
+     * @see #getUseCompatPadding()
+     */
+    public void setUseCompatPadding(boolean useCompatPadding) {
+        if (mCompatPadding != useCompatPadding) {
+            mCompatPadding = useCompatPadding;
+            mImpl.onCompatShadowChanged();
+        }
+    }
+
+    /**
+     * Returns whether FloatingActionButton will add inner padding on platforms Lollipop and after.
+     *
+     * @return true if FloatingActionButton is adding inner padding on platforms Lollipop and after,
+     * to ensure consistent dimensions on all platforms.
+     *
+     * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding
+     * @see #setUseCompatPadding(boolean)
+     */
+    public boolean getUseCompatPadding() {
+        return mCompatPadding;
+    }
+
+    @Nullable
+    private InternalVisibilityChangedListener wrapOnVisibilityChangedListener(
+            @Nullable final OnVisibilityChangedListener listener) {
+        if (listener == null) {
+            return null;
+        }
+
+        return new InternalVisibilityChangedListener() {
+            @Override
+            public void onShown() {
+                listener.onShown(FloatingActionButton.this);
+            }
+
+            @Override
+            public void onHidden() {
+                listener.onHidden(FloatingActionButton.this);
+            }
+        };
     }
 
     final int getSizeDimension() {
@@ -261,6 +377,18 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mImpl.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mImpl.onDetachedFromWindow();
+    }
+
+    @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
         mImpl.onDrawableStateChanged(getDrawableState());
@@ -273,6 +401,33 @@
         mImpl.jumpDrawableToCurrentState();
     }
 
+    /**
+     * Return in {@code rect} the bounds of the actual floating action button content in view-local
+     * coordinates. This is defined as anything within any visible shadow.
+     *
+     * @return true if this view actually has been laid out and has a content rect, else false.
+     */
+    public boolean getContentRect(@NonNull Rect rect) {
+        if (ViewCompat.isLaidOut(this)) {
+            rect.set(0, 0, getWidth(), getHeight());
+            rect.left += mShadowPadding.left;
+            rect.top += mShadowPadding.top;
+            rect.right -= mShadowPadding.right;
+            rect.bottom -= mShadowPadding.bottom;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the FloatingActionButton's background, minus any compatible shadow implementation.
+     */
+    @NonNull
+    public Drawable getContentBackground() {
+        return mImpl.getContentBackground();
+    }
+
     private static int resolveAdjustedSize(int desiredSize, int measureSpec) {
         int result = desiredSize;
         int specMode = MeasureSpec.getMode(measureSpec);
@@ -324,6 +479,8 @@
         // because we can use view translation properties which greatly simplifies the code.
         private static final boolean SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11;
 
+        private ValueAnimatorCompat mFabTranslationYAnimator;
+        private float mFabTranslationY;
         private Rect mTmpRect;
 
         @Override
@@ -346,24 +503,6 @@
             return false;
         }
 
-        @Override
-        public void onDependentViewRemoved(CoordinatorLayout parent, FloatingActionButton child,
-                View dependency) {
-            if (dependency instanceof Snackbar.SnackbarLayout) {
-                // If the removed view is a SnackbarLayout, we will animate back to our normal
-                // position
-                if (ViewCompat.getTranslationY(child) != 0f) {
-                    ViewCompat.animate(child)
-                            .translationY(0f)
-                            .scaleX(1f)
-                            .scaleY(1f)
-                            .alpha(1f)
-                            .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                            .setListener(null);
-                }
-            }
-        }
-
         private boolean updateFabVisibility(CoordinatorLayout parent,
                 AppBarLayout appBarLayout, FloatingActionButton child) {
             final CoordinatorLayout.LayoutParams lp =
@@ -374,6 +513,11 @@
                 return false;
             }
 
+            if (child.getUserSetVisibility() != VISIBLE) {
+                // The view isn't set to be visible so skip changing it's visibility
+                return false;
+            }
+
             if (mTmpRect == null) {
                 mTmpRect = new Rect();
             }
@@ -384,22 +528,57 @@
 
             if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
                 // If the anchor's bottom is below the seam, we'll animate our FAB out
-                child.hide();
+                child.hide(null, false);
             } else {
                 // Else, we'll animate our FAB back in
-                child.show();
+                child.show(null, false);
             }
             return true;
         }
 
         private void updateFabTranslationForSnackbar(CoordinatorLayout parent,
-                FloatingActionButton fab, View snackbar) {
+                final FloatingActionButton fab, View snackbar) {
             if (fab.getVisibility() != View.VISIBLE) {
                 return;
             }
 
-            final float translationY = getFabTranslationYForSnackbar(parent, fab);
-            ViewCompat.setTranslationY(fab, translationY);
+            final float targetTransY = getFabTranslationYForSnackbar(parent, fab);
+            if (mFabTranslationY == targetTransY) {
+                // We're already at (or currently animating to) the target value, return...
+                return;
+            }
+
+            final float currentTransY = ViewCompat.getTranslationY(fab);
+
+            // Make sure that any current animation is cancelled
+            if (mFabTranslationYAnimator != null && mFabTranslationYAnimator.isRunning()) {
+                mFabTranslationYAnimator.cancel();
+            }
+
+            if (Math.abs(currentTransY - targetTransY) > (fab.getHeight() * 0.667f)) {
+                // If the FAB will be travelling by more than 2/3 of it's height, let's animate
+                // it instead
+                if (mFabTranslationYAnimator == null) {
+                    mFabTranslationYAnimator = ViewUtils.createAnimator();
+                    mFabTranslationYAnimator.setInterpolator(
+                            AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+                    mFabTranslationYAnimator.setUpdateListener(
+                            new ValueAnimatorCompat.AnimatorUpdateListener() {
+                                @Override
+                                public void onAnimationUpdate(ValueAnimatorCompat animator) {
+                                    ViewCompat.setTranslationY(fab,
+                                            animator.getAnimatedFloatValue());
+                                }
+                            });
+                }
+                mFabTranslationYAnimator.setFloatValues(currentTransY, targetTransY);
+                mFabTranslationYAnimator.start();
+            } else {
+                // Now update the translation Y
+                ViewCompat.setTranslationY(fab, targetTransY);
+            }
+
+            mFabTranslationY = targetTransY;
         }
 
         private float getFabTranslationYForSnackbar(CoordinatorLayout parent,
@@ -470,4 +649,27 @@
             }
         }
     }
+
+    /**
+     * Returns the backward compatible elevation of the FloatingActionButton.
+     *
+     * @return the backward compatible elevation in pixels.
+     * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation
+     * @see #setFloatingActionButtonElevation(float)
+     */
+    public float getFloatingActionButtonElevation() {
+        return mImpl.getElevation();
+    }
+
+    /**
+     * Updates the backward compatible elevation of the FloatingActionButton.
+     *
+     * @param elevation The backward compatible elevation in pixels.
+     * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation
+     * @see #getFloatingActionButtonElevation()
+     * @see #setUseCompatPadding(boolean)
+     */
+    public void setFloatingActionButtonElevation(float elevation) {
+        mImpl.setElevation(elevation);
+    }
 }
diff --git a/design/src/android/support/design/widget/HeaderBehavior.java b/design/src/android/support/design/widget/HeaderBehavior.java
new file mode 100644
index 0000000..9924d48
--- /dev/null
+++ b/design/src/android/support/design/widget/HeaderBehavior.java
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.support.design.widget.CoordinatorLayout.Behavior;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.VelocityTrackerCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ScrollerCompat;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+/**
+ * The {@link Behavior} for a view that sits vertically above scrolling a view.
+ * See {@link HeaderScrollingViewBehavior}.
+ */
+abstract class HeaderBehavior<V extends View> extends ViewOffsetBehavior<V> {
+
+    private static final int INVALID_POINTER = -1;
+
+    private Runnable mFlingRunnable;
+    private ScrollerCompat mScroller;
+
+    private boolean mIsBeingDragged;
+    private int mActivePointerId = INVALID_POINTER;
+    private int mLastMotionY;
+    private int mTouchSlop = -1;
+    private VelocityTracker mVelocityTracker;
+
+    public HeaderBehavior() {}
+
+    public HeaderBehavior(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
+        if (mTouchSlop < 0) {
+            mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
+        }
+
+        final int action = ev.getAction();
+
+        // Shortcut since we're being dragged
+        if (action == MotionEvent.ACTION_MOVE && mIsBeingDragged) {
+            return true;
+        }
+
+        switch (MotionEventCompat.getActionMasked(ev)) {
+            case MotionEvent.ACTION_DOWN: {
+                mIsBeingDragged = false;
+                final int x = (int) ev.getX();
+                final int y = (int) ev.getY();
+                if (canDragView(child) && parent.isPointInChildBounds(child, x, y)) {
+                    mLastMotionY = y;
+                    mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+                    ensureVelocityTracker();
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                final int activePointerId = mActivePointerId;
+                if (activePointerId == INVALID_POINTER) {
+                    // If we don't have a valid id, the touch down wasn't on content.
+                    break;
+                }
+                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
+                if (pointerIndex == -1) {
+                    break;
+                }
+
+                final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
+                final int yDiff = Math.abs(y - mLastMotionY);
+                if (yDiff > mTouchSlop) {
+                    mIsBeingDragged = true;
+                    mLastMotionY = y;
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP: {
+                mIsBeingDragged = false;
+                mActivePointerId = INVALID_POINTER;
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.recycle();
+                    mVelocityTracker = null;
+                }
+                break;
+            }
+        }
+
+        if (mVelocityTracker != null) {
+            mVelocityTracker.addMovement(ev);
+        }
+
+        return mIsBeingDragged;
+    }
+
+    @Override
+    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
+        if (mTouchSlop < 0) {
+            mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
+        }
+
+        switch (MotionEventCompat.getActionMasked(ev)) {
+            case MotionEvent.ACTION_DOWN: {
+                final int x = (int) ev.getX();
+                final int y = (int) ev.getY();
+
+                if (parent.isPointInChildBounds(child, x, y) && canDragView(child)) {
+                    mLastMotionY = y;
+                    mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+                    ensureVelocityTracker();
+                } else {
+                    return false;
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                final int activePointerIndex = MotionEventCompat.findPointerIndex(ev,
+                        mActivePointerId);
+                if (activePointerIndex == -1) {
+                    return false;
+                }
+
+                final int y = (int) MotionEventCompat.getY(ev, activePointerIndex);
+                int dy = mLastMotionY - y;
+
+                if (!mIsBeingDragged && Math.abs(dy) > mTouchSlop) {
+                    mIsBeingDragged = true;
+                    if (dy > 0) {
+                        dy -= mTouchSlop;
+                    } else {
+                        dy += mTouchSlop;
+                    }
+                }
+
+                if (mIsBeingDragged) {
+                    mLastMotionY = y;
+                    // We're being dragged so scroll the ABL
+                    scroll(parent, child, dy, getMaxDragOffset(child), 0);
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_UP:
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.addMovement(ev);
+                    mVelocityTracker.computeCurrentVelocity(1000);
+                    float yvel = VelocityTrackerCompat.getYVelocity(mVelocityTracker,
+                            mActivePointerId);
+                    fling(parent, child, -getScrollRangeForDragFling(child), 0, yvel);
+                }
+                // $FALLTHROUGH
+            case MotionEvent.ACTION_CANCEL: {
+                mIsBeingDragged = false;
+                mActivePointerId = INVALID_POINTER;
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.recycle();
+                    mVelocityTracker = null;
+                }
+                break;
+            }
+        }
+
+        if (mVelocityTracker != null) {
+            mVelocityTracker.addMovement(ev);
+        }
+
+        return true;
+    }
+
+    int setHeaderTopBottomOffset(CoordinatorLayout parent, V header, int newOffset) {
+        return setHeaderTopBottomOffset(parent, header, newOffset,
+                Integer.MIN_VALUE, Integer.MAX_VALUE);
+    }
+
+    int setHeaderTopBottomOffset(CoordinatorLayout parent, V header, int newOffset,
+            int minOffset, int maxOffset) {
+        final int curOffset = getTopAndBottomOffset();
+        int consumed = 0;
+
+        if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
+            // If we have some scrolling range, and we're currently within the min and max
+            // offsets, calculate a new offset
+            newOffset = MathUtils.constrain(newOffset, minOffset, maxOffset);
+
+            if (curOffset != newOffset) {
+                setTopAndBottomOffset(newOffset);
+                // Update how much dy we have consumed
+                consumed = curOffset - newOffset;
+            }
+        }
+
+        return consumed;
+    }
+
+    int getTopBottomOffsetForScrollingSibling() {
+        return getTopAndBottomOffset();
+    }
+
+    final int scroll(CoordinatorLayout coordinatorLayout, V header,
+            int dy, int minOffset, int maxOffset) {
+        return setHeaderTopBottomOffset(coordinatorLayout, header,
+                getTopBottomOffsetForScrollingSibling() - dy, minOffset, maxOffset);
+    }
+
+    final boolean fling(CoordinatorLayout coordinatorLayout, V layout, int minOffset,
+            int maxOffset, float velocityY) {
+        if (mFlingRunnable != null) {
+            layout.removeCallbacks(mFlingRunnable);
+            mFlingRunnable = null;
+        }
+
+        if (mScroller == null) {
+            mScroller = ScrollerCompat.create(layout.getContext());
+        }
+
+        mScroller.fling(
+                0, getTopAndBottomOffset(), // curr
+                0, Math.round(velocityY), // velocity.
+                0, 0, // x
+                minOffset, maxOffset); // y
+
+        if (mScroller.computeScrollOffset()) {
+            mFlingRunnable = new FlingRunnable(coordinatorLayout, layout);
+            ViewCompat.postOnAnimation(layout, mFlingRunnable);
+            return true;
+        } else {
+            onFlingFinished(coordinatorLayout, layout);
+            return false;
+        }
+    }
+
+    /**
+     * Called when a fling has finished, or the fling was initiated but there wasn't enough
+     * velocity to start it.
+     */
+    void onFlingFinished(CoordinatorLayout parent, V layout) {
+        // no-op
+    }
+
+    /**
+     * Return true if the view can be dragged.
+     */
+    boolean canDragView(V view) {
+        return false;
+    }
+
+    /**
+     * Returns the maximum px offset when {@code view} is being dragged.
+     */
+    int getMaxDragOffset(V view) {
+        return -view.getHeight();
+    }
+
+    int getScrollRangeForDragFling(V view) {
+        return view.getHeight();
+    }
+
+    private void ensureVelocityTracker() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+    }
+
+    private class FlingRunnable implements Runnable {
+        private final CoordinatorLayout mParent;
+        private final V mLayout;
+
+        FlingRunnable(CoordinatorLayout parent, V layout) {
+            mParent = parent;
+            mLayout = layout;
+        }
+
+        @Override
+        public void run() {
+            if (mLayout != null && mScroller != null) {
+                if (mScroller.computeScrollOffset()) {
+                    setHeaderTopBottomOffset(mParent, mLayout, mScroller.getCurrY());
+                    // Post ourselves so that we run on the next animation
+                    ViewCompat.postOnAnimation(mLayout, this);
+                } else {
+                    onFlingFinished(mParent, mLayout);
+                }
+            }
+        }
+    }
+}
diff --git a/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java b/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java
new file mode 100644
index 0000000..ac24ca2
--- /dev/null
+++ b/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.support.design.widget.CoordinatorLayout.Behavior;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+/**
+ * The {@link Behavior} for a scrolling view that is positioned vertically below another view.
+ * See {@link HeaderBehavior}.
+ */
+abstract class HeaderScrollingViewBehavior extends ViewOffsetBehavior<View> {
+
+    public HeaderScrollingViewBehavior() {}
+
+    public HeaderScrollingViewBehavior(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onMeasureChild(CoordinatorLayout parent, View child,
+            int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec,
+            int heightUsed) {
+        final int childLpHeight = child.getLayoutParams().height;
+        if (childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
+                || childLpHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            // If the menu's height is set to match_parent/wrap_content then measure it
+            // with the maximum visible height
+
+            final List<View> dependencies = parent.getDependencies(child);
+            if (dependencies.isEmpty()) {
+                // If we don't have any dependencies, return false
+                return false;
+            }
+
+            final View header = findFirstDependency(dependencies);
+            if (header != null && ViewCompat.isLaidOut(header)) {
+                if (ViewCompat.getFitsSystemWindows(header)) {
+                    // If the header is fitting system windows then we need to also,
+                    // otherwise we'll get CoL's compatible layout functionality
+                    ViewCompat.setFitsSystemWindows(child, true);
+                }
+
+                int availableHeight = View.MeasureSpec.getSize(parentHeightMeasureSpec);
+                if (availableHeight == 0) {
+                    // If the measure spec doesn't specify a size, use the current height
+                    availableHeight = parent.getHeight();
+                }
+
+                final int height = availableHeight - header.getMeasuredHeight()
+                        + getScrollRange(header);
+                final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height,
+                        childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
+                                ? View.MeasureSpec.EXACTLY
+                                : View.MeasureSpec.AT_MOST);
+
+                // Now measure the scrolling menu with the correct height
+                parent.onMeasureChild(child, parentWidthMeasureSpec,
+                        widthUsed, heightMeasureSpec, heightUsed);
+
+                return true;
+            }
+        }
+        return false;
+    }
+
+    abstract View findFirstDependency(List<View> views);
+
+    int getScrollRange(View v) {
+        return v.getMeasuredHeight();
+    }
+}
\ No newline at end of file
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index 4e325fa..57882db 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -34,10 +34,12 @@
 import android.support.design.internal.NavigationMenuPresenter;
 import android.support.design.internal.ScrimInsetsFrameLayout;
 import android.support.v4.content.ContextCompat;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.ViewCompat;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.Menu;
@@ -95,6 +97,8 @@
     public NavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        ThemeUtils.checkAppCompatTheme(context);
+
         // Create the menu
         mMenu = new NavigationMenu(context);
 
@@ -265,6 +269,26 @@
     }
 
     /**
+     * Gets the number of headers in this NavigationView.
+     *
+     * @return A positive integer representing the number of headers.
+     */
+    public int getHeaderCount() {
+        return mPresenter.getHeaderCount();
+    }
+
+    /**
+     * Gets the header view at the specified position.
+     *
+     * @param index The position at which to get the view from.
+     * @return The header view the specified position or null if the position does not exist in this
+     * NavigationView.
+     */
+    public View getHeaderView(int index) {
+        return mPresenter.getHeaderView(index);
+    }
+
+    /**
      * Returns the tint which is applied to our item's icons.
      *
      * @see #setItemIconTintList(ColorStateList)
@@ -414,9 +438,9 @@
     public static class SavedState extends BaseSavedState {
         public Bundle menuState;
 
-        public SavedState(Parcel in) {
+        public SavedState(Parcel in, ClassLoader loader) {
             super(in);
-            menuState = in.readBundle();
+            menuState = in.readBundle(loader);
         }
 
         public SavedState(Parcelable superState) {
@@ -430,17 +454,17 @@
         }
 
         public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
+                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
             @Override
-            public SavedState createFromParcel(Parcel parcel) {
-                return new SavedState(parcel);
+            public SavedState createFromParcel(Parcel parcel, ClassLoader loader) {
+                return new SavedState(parcel, loader);
             }
 
             @Override
             public SavedState[] newArray(int size) {
                 return new SavedState[size];
             }
-        };
+        });
     }
 
 }
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index b04c706..a328d98 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -169,18 +169,21 @@
         });
     }
 
-    private final ViewGroup mParent;
+    private final ViewGroup mTargetParent;
     private final Context mContext;
     private final SnackbarLayout mView;
     private int mDuration;
     private Callback mCallback;
 
     private Snackbar(ViewGroup parent) {
-        mParent = parent;
+        mTargetParent = parent;
         mContext = parent.getContext();
 
+        ThemeUtils.checkAppCompatTheme(mContext);
+
         LayoutInflater inflater = LayoutInflater.from(mContext);
-        mView = (SnackbarLayout) inflater.inflate(R.layout.design_layout_snackbar, mParent, false);
+        mView = (SnackbarLayout) inflater.inflate(
+                R.layout.design_layout_snackbar, mTargetParent, false);
     }
 
     /**
@@ -401,10 +404,18 @@
     }
 
     /**
-     * Return whether this Snackbar is currently being shown.
+     * Return whether this {@link Snackbar} is currently being shown.
      */
     public boolean isShown() {
-        return mView.isShown();
+        return SnackbarManager.getInstance().isCurrent(mManagerCallback);
+    }
+
+    /**
+     * Returns whether this {@link Snackbar} is currently being shown, or is queued to be
+     * shown next.
+     */
+    public boolean isShownOrQueued() {
+        return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback);
     }
 
     private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
@@ -454,9 +465,30 @@
                 ((CoordinatorLayout.LayoutParams) lp).setBehavior(behavior);
             }
 
-            mParent.addView(mView);
+            mTargetParent.addView(mView);
         }
 
+        mView.setOnAttachStateChangeListener(new SnackbarLayout.OnAttachStateChangeListener() {
+            @Override
+            public void onViewAttachedToWindow(View v) {}
+
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+                if (isShownOrQueued()) {
+                    // If we haven't already been dismissed then this event is coming from a
+                    // non-user initiated action. Hence we need to make sure that we callback
+                    // and keep our state up to date. We need to post the call since removeView()
+                    // will call through to onDetachedFromWindow and thus overflow.
+                    sHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            onViewHidden(Callback.DISMISS_EVENT_MANUAL);
+                        }
+                    });
+                }
+            }
+        });
+
         if (ViewCompat.isLaidOut(mView)) {
             // If the view is already laid out, animate it now
             animateViewIn();
@@ -475,7 +507,8 @@
     private void animateViewIn() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
             ViewCompat.setTranslationY(mView, mView.getHeight());
-            ViewCompat.animate(mView).translationY(0f)
+            ViewCompat.animate(mView)
+                    .translationY(0f)
                     .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
                     .setDuration(ANIMATION_DURATION)
                     .setListener(new ViewPropertyAnimatorListenerAdapter() {
@@ -494,7 +527,8 @@
                         }
                     }).start();
         } else {
-            Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.design_snackbar_in);
+            Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
+                    R.anim.design_snackbar_in);
             anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
             anim.setDuration(ANIMATION_DURATION);
             anim.setAnimationListener(new Animation.AnimationListener() {
@@ -518,7 +552,8 @@
 
     private void animateViewOut(final int event) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            ViewCompat.animate(mView).translationY(mView.getHeight())
+            ViewCompat.animate(mView)
+                    .translationY(mView.getHeight())
                     .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
                     .setDuration(ANIMATION_DURATION)
                     .setListener(new ViewPropertyAnimatorListenerAdapter() {
@@ -561,14 +596,17 @@
     }
 
     private void onViewHidden(int event) {
-        // First remove the view from the parent
-        mParent.removeView(mView);
+        // First tell the SnackbarManager that it has been dismissed
+        SnackbarManager.getInstance().onDismissed(mManagerCallback);
         // Now call the dismiss listener (if available)
         if (mCallback != null) {
             mCallback.onDismissed(this, event);
         }
-        // Finally, tell the SnackbarManager that it has been dismissed
-        SnackbarManager.getInstance().onDismissed(mManagerCallback);
+        // Lastly, remove the view from the parent (if attached)
+        final ViewParent parent = mView.getParent();
+        if (parent instanceof ViewGroup) {
+            ((ViewGroup) parent).removeView(mView);
+        }
     }
 
     /**
@@ -600,10 +638,16 @@
         private int mMaxInlineActionWidth;
 
         interface OnLayoutChangeListener {
-            public void onLayoutChange(View view, int left, int top, int right, int bottom);
+            void onLayoutChange(View view, int left, int top, int right, int bottom);
+        }
+
+        interface OnAttachStateChangeListener {
+            void onViewAttachedToWindow(View v);
+            void onViewDetachedFromWindow(View v);
         }
 
         private OnLayoutChangeListener mOnLayoutChangeListener;
+        private OnAttachStateChangeListener mOnAttachStateChangeListener;
 
         public SnackbarLayout(Context context) {
             this(context, null);
@@ -627,6 +671,9 @@
             // in the layout since older versions of the Android do not inflate includes with
             // the correct Context.
             LayoutInflater.from(context).inflate(R.layout.design_layout_snackbar_include, this);
+
+            ViewCompat.setAccessibilityLiveRegion(this,
+                    ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
         }
 
         @Override
@@ -710,10 +757,30 @@
             }
         }
 
+        @Override
+        protected void onAttachedToWindow() {
+            super.onAttachedToWindow();
+            if (mOnAttachStateChangeListener != null) {
+                mOnAttachStateChangeListener.onViewAttachedToWindow(this);
+            }
+        }
+
+        @Override
+        protected void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+            if (mOnAttachStateChangeListener != null) {
+                mOnAttachStateChangeListener.onViewDetachedFromWindow(this);
+            }
+        }
+
         void setOnLayoutChangeListener(OnLayoutChangeListener onLayoutChangeListener) {
             mOnLayoutChangeListener = onLayoutChangeListener;
         }
 
+        void setOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
+            mOnAttachStateChangeListener = listener;
+        }
+
         private boolean updateViewsWithinLayout(final int orientation,
                 final int messagePadTop, final int messagePadBottom) {
             boolean changed = false;
@@ -743,6 +810,11 @@
 
     final class Behavior extends SwipeDismissBehavior<SnackbarLayout> {
         @Override
+        public boolean canSwipeDismissView(View child) {
+            return child instanceof SnackbarLayout;
+        }
+
+        @Override
         public boolean onInterceptTouchEvent(CoordinatorLayout parent, SnackbarLayout child,
                 MotionEvent event) {
             // We want to make sure that we disable any Snackbar timeouts if the user is
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
index 253ee92..be2f024 100644
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ b/design/src/android/support/design/widget/SnackbarManager.java
@@ -69,7 +69,7 @@
 
     public void show(int duration, Callback callback) {
         synchronized (mLock) {
-            if (isCurrentSnackbar(callback)) {
+            if (isCurrentSnackbarLocked(callback)) {
                 // Means that the callback is already in the queue. We'll just update the duration
                 mCurrentSnackbar.duration = duration;
 
@@ -78,7 +78,7 @@
                 mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
                 scheduleTimeoutLocked(mCurrentSnackbar);
                 return;
-            } else if (isNextSnackbar(callback)) {
+            } else if (isNextSnackbarLocked(callback)) {
                 // We'll just update the duration
                 mNextSnackbar.duration = duration;
             } else {
@@ -101,9 +101,9 @@
 
     public void dismiss(Callback callback, int event) {
         synchronized (mLock) {
-            if (isCurrentSnackbar(callback)) {
+            if (isCurrentSnackbarLocked(callback)) {
                 cancelSnackbarLocked(mCurrentSnackbar, event);
-            } else if (isNextSnackbar(callback)) {
+            } else if (isNextSnackbarLocked(callback)) {
                 cancelSnackbarLocked(mNextSnackbar, event);
             }
         }
@@ -115,7 +115,7 @@
      */
     public void onDismissed(Callback callback) {
         synchronized (mLock) {
-            if (isCurrentSnackbar(callback)) {
+            if (isCurrentSnackbarLocked(callback)) {
                 // If the callback is from a Snackbar currently show, remove it and show a new one
                 mCurrentSnackbar = null;
                 if (mNextSnackbar != null) {
@@ -131,7 +131,7 @@
      */
     public void onShown(Callback callback) {
         synchronized (mLock) {
-            if (isCurrentSnackbar(callback)) {
+            if (isCurrentSnackbarLocked(callback)) {
                 scheduleTimeoutLocked(mCurrentSnackbar);
             }
         }
@@ -139,7 +139,7 @@
 
     public void cancelTimeout(Callback callback) {
         synchronized (mLock) {
-            if (isCurrentSnackbar(callback)) {
+            if (isCurrentSnackbarLocked(callback)) {
                 mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
             }
         }
@@ -147,12 +147,24 @@
 
     public void restoreTimeout(Callback callback) {
         synchronized (mLock) {
-            if (isCurrentSnackbar(callback)) {
+            if (isCurrentSnackbarLocked(callback)) {
                 scheduleTimeoutLocked(mCurrentSnackbar);
             }
         }
     }
 
+    public boolean isCurrent(Callback callback) {
+        synchronized (mLock) {
+            return isCurrentSnackbarLocked(callback);
+        }
+    }
+
+    public boolean isCurrentOrNext(Callback callback) {
+        synchronized (mLock) {
+            return isCurrentSnackbarLocked(callback) || isNextSnackbarLocked(callback);
+        }
+    }
+
     private static class SnackbarRecord {
         private final WeakReference<Callback> callback;
         private int duration;
@@ -191,11 +203,11 @@
         return false;
     }
 
-    private boolean isCurrentSnackbar(Callback callback) {
+    private boolean isCurrentSnackbarLocked(Callback callback) {
         return mCurrentSnackbar != null && mCurrentSnackbar.isSnackbar(callback);
     }
 
-    private boolean isNextSnackbar(Callback callback) {
+    private boolean isNextSnackbarLocked(Callback callback) {
         return mNextSnackbar != null && mNextSnackbar.isSnackbar(callback);
     }
 
diff --git a/design/src/android/support/design/widget/SwipeDismissBehavior.java b/design/src/android/support/design/widget/SwipeDismissBehavior.java
index fc29201..e059fe5 100644
--- a/design/src/android/support/design/widget/SwipeDismissBehavior.java
+++ b/design/src/android/support/design/widget/SwipeDismissBehavior.java
@@ -17,6 +17,7 @@
 package android.support.design.widget;
 
 import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
 import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.ViewDragHelper;
@@ -198,13 +199,27 @@
         return false;
     }
 
+    /**
+     * Called when the user's input indicates that they want to swipe the given view.
+     *
+     * @param view View the user is attempting to swipe
+     * @return true if the view can be dismissed via swiping, false otherwise
+     */
+    public boolean canSwipeDismissView(@NonNull View view) {
+        return true;
+    }
+
     private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
         private int mOriginalCapturedViewLeft;
 
         @Override
         public boolean tryCaptureView(View child, int pointerId) {
-            mOriginalCapturedViewLeft = child.getLeft();
-            return true;
+            return canSwipeDismissView(child);
+        }
+
+        @Override
+        public void onViewCaptured(View capturedChild, int activePointerId) {
+            mOriginalCapturedViewLeft = capturedChild.getLeft();
         }
 
         @Override
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 7eee77b..fe1a105 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -19,7 +19,9 @@
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.database.DataSetObserver;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.drawable.Drawable;
@@ -32,14 +34,18 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
 import android.support.design.R;
+import android.support.v4.util.Pools;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewPager;
+import android.support.v4.widget.TextViewCompat;
 import android.support.v7.app.ActionBar;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.widget.AppCompatDrawableManager;
+import android.text.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -81,20 +87,16 @@
  * notified when any tab's selection state has been changed.
  * <p>
  * If you're using a {@link android.support.v4.view.ViewPager} together
- * with this layout, you can use {@link #setTabsFromPagerAdapter(PagerAdapter)} which will populate
- * the tabs using the given {@link PagerAdapter}'s page titles. You should also use a
- * {@link TabLayoutOnPageChangeListener} to forward the scroll and selection changes to this
- * layout like so:
- * <pre>
- * ViewPager viewPager = ...;
- * TabLayout tabLayout = ...;
- * viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(tabLayout));
- * </pre>
+ * with this layout, you can use {@link #setupWithViewPager(ViewPager)} to link the two together.
+ * This layout will be automatically populated from the {@link PagerAdapter}'s page titles.</p>
  *
  * @see <a href="http://www.google.com/design/spec/components/tabs.html">Tabs</a>
  */
 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
+    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
@@ -102,6 +104,8 @@
 
     private static final int ANIMATION_DURATION = 300;
 
+    private static final Pools.Pool<Tab> sTabPool = new Pools.SynchronizedPool<>(16);
+
     /**
      * Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab
      * labels and a larger number of tabs. They are best used for browsing contexts in touch
@@ -193,12 +197,15 @@
 
     private int mTabTextAppearance;
     private ColorStateList mTabTextColors;
+    private float mTabTextSize;
+    private float mTabTextMultiLineSize;
 
     private final int mTabBackgroundResId;
 
-    private final int mTabMinWidth;
     private int mTabMaxWidth = Integer.MAX_VALUE;
+    private final int mRequestedTabMinWidth;
     private final int mRequestedTabMaxWidth;
+    private final int mScrollableTabMinWidth;
 
     private int mContentInsetStart;
 
@@ -209,7 +216,14 @@
     private View.OnClickListener mTabClickListener;
 
     private ValueAnimatorCompat mScrollAnimator;
-    private ValueAnimatorCompat mIndicatorAnimator;
+
+    private ViewPager mViewPager;
+    private PagerAdapter mPagerAdapter;
+    private DataSetObserver mPagerAdapterObserver;
+    private TabLayoutOnPageChangeListener mPageChangeListener;
+
+    // Pool we use as a simple RecyclerBin
+    private final Pools.Pool<TabView> mTabViewPool = new Pools.SimplePool<>(12);
 
     public TabLayout(Context context) {
         this(context, null);
@@ -222,10 +236,10 @@
     public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        ThemeUtils.checkAppCompatTheme(context);
+
         // Disable the Scroll Bar
         setHorizontalScrollBarEnabled(false);
-        // Set us to fill the View port
-        setFillViewport(true);
 
         // Add the TabStrip
         mTabStrip = new SlidingTabStrip(context);
@@ -238,9 +252,6 @@
                 a.getDimensionPixelSize(R.styleable.TabLayout_tabIndicatorHeight, 0));
         mTabStrip.setSelectedIndicatorColor(a.getColor(R.styleable.TabLayout_tabIndicatorColor, 0));
 
-        mTabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
-                R.style.TextAppearance_Design_Tab);
-
         mTabPaddingStart = mTabPaddingTop = mTabPaddingEnd = mTabPaddingBottom = a
                 .getDimensionPixelSize(R.styleable.TabLayout_tabPadding, 0);
         mTabPaddingStart = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingStart,
@@ -252,8 +263,18 @@
         mTabPaddingBottom = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingBottom,
                 mTabPaddingBottom);
 
-        // Text colors come from the text appearance first
-        mTabTextColors = loadTextColorFromTextAppearance(mTabTextAppearance);
+        mTabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
+                R.style.TextAppearance_Design_Tab);
+
+        // Text colors/sizes come from the text appearance first
+        final TypedArray ta = context.obtainStyledAttributes(mTabTextAppearance,
+                R.styleable.TextAppearance);
+        try {
+            mTabTextSize = ta.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, 0);
+            mTabTextColors = ta.getColorStateList(R.styleable.TextAppearance_android_textColor);
+        } finally {
+            ta.recycle();
+        }
 
         if (a.hasValue(R.styleable.TabLayout_tabTextColor)) {
             // If we have an explicit text color set, use it instead
@@ -268,14 +289,21 @@
             mTabTextColors = createColorStateList(mTabTextColors.getDefaultColor(), selected);
         }
 
-        mTabMinWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMinWidth, 0);
-        mRequestedTabMaxWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMaxWidth, 0);
+        mRequestedTabMinWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMinWidth,
+                INVALID_WIDTH);
+        mRequestedTabMaxWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMaxWidth,
+                INVALID_WIDTH);
         mTabBackgroundResId = a.getResourceId(R.styleable.TabLayout_tabBackground, 0);
         mContentInsetStart = a.getDimensionPixelSize(R.styleable.TabLayout_tabContentStart, 0);
         mMode = a.getInt(R.styleable.TabLayout_tabMode, MODE_FIXED);
         mTabGravity = a.getInt(R.styleable.TabLayout_tabGravity, GRAVITY_FILL);
         a.recycle();
 
+        // TODO add attr for these
+        final Resources res = getResources();
+        mTabTextMultiLineSize = res.getDimensionPixelSize(R.dimen.design_tab_text_size_2line);
+        mScrollableTabMinWidth = res.getDimensionPixelSize(R.dimen.design_tab_scrollable_min_width);
+
         // Now apply the tab mode and gravity
         applyModeAndGravity();
     }
@@ -309,20 +337,30 @@
      * @param updateSelectedText Whether to update the text's selected state.
      */
     public void setScrollPosition(int position, float positionOffset, boolean updateSelectedText) {
-        if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
-            return;
-        }
-        if (position < 0 || position >= mTabStrip.getChildCount()) {
+        setScrollPosition(position, positionOffset, updateSelectedText, true);
+    }
+
+    private void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
+            boolean updateIndicatorPosition) {
+        final int roundedPosition = Math.round(position + positionOffset);
+        if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {
             return;
         }
 
-        // Set the indicator position and update the scroll to match
-        mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);
+        // Set the indicator position, if enabled
+        if (updateIndicatorPosition) {
+            mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);
+        }
+
+        // Now update the scroll position, canceling any running animation
+        if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
+            mScrollAnimator.cancel();
+        }
         scrollTo(calculateScrollXForTab(position, positionOffset), 0);
 
-        // Update the 'selected state' view as we scroll
+        // Update the 'selected state' view as we scroll, if enabled
         if (updateSelectedText) {
-            setSelectedTabView(Math.round(position + positionOffset));
+            setSelectedTabView(roundedPosition);
         }
     }
 
@@ -407,7 +445,8 @@
      */
     @NonNull
     public Tab newTab() {
-        return new Tab(this);
+        final Tab poolTab = sTabPool.acquire();
+        return poolTab != null ? poolTab : new Tab(this);
     }
 
     /**
@@ -460,9 +499,10 @@
         final int selectedTabPosition = mSelectedTab != null ? mSelectedTab.getPosition() : 0;
         removeTabViewAt(position);
 
-        Tab removedTab = mTabs.remove(position);
+        final Tab removedTab = mTabs.remove(position);
         if (removedTab != null) {
-            removedTab.setPosition(Tab.INVALID_POSITION);
+            removedTab.reset();
+            sTabPool.release(removedTab);
         }
 
         final int newTabCount = mTabs.size();
@@ -480,12 +520,15 @@
      */
     public void removeAllTabs() {
         // Remove all the views
-        mTabStrip.removeAllViews();
+        for (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {
+            removeTabViewAt(i);
+        }
 
-        for (Iterator<Tab> i = mTabs.iterator(); i.hasNext(); ) {
-            Tab tab = i.next();
-            tab.setPosition(Tab.INVALID_POSITION);
+        for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext();) {
+            final Tab tab = i.next();
             i.remove();
+            tab.reset();
+            sTabPool.release(tab);
         }
 
         mSelectedTab = null;
@@ -571,57 +614,102 @@
     /**
      * The one-stop shop for setting up this {@link TabLayout} with a {@link ViewPager}.
      *
-     * <p>This method will:
-     * <ul>
-     *     <li>Add a {@link ViewPager.OnPageChangeListener} that will forward events to
-     *     this TabLayout.</li>
-     *     <li>Populate the TabLayout's tabs from the ViewPager's {@link PagerAdapter}.</li>
-     *     <li>Set our {@link TabLayout.OnTabSelectedListener} which will forward
-     *     selected events to the ViewPager</li>
-     * </ul>
-     * </p>
+     * <p>This method will link the given ViewPager and this TabLayout together so that any
+     * changes in one are automatically reflected in the other. This includes adapter changes,
+     * scroll state changes, and clicks. The tabs displayed in this layout will be populated
+     * from the ViewPager adapter's page titles.</p>
      *
-     * @see #setTabsFromPagerAdapter(PagerAdapter)
-     * @see TabLayoutOnPageChangeListener
-     * @see ViewPagerOnTabSelectedListener
+     * <p>After this method is called, you will not need this method again unless you want
+     * to change the linked ViewPager.</p>
+     *
+     * <p>If the given ViewPager is non-null, it needs to already have a
+     * {@link PagerAdapter} set.</p>
+     *
+     * @param viewPager The ViewPager to link, or {@code null} to clear any previous link.
      */
-    public void setupWithViewPager(@NonNull ViewPager viewPager) {
-        final PagerAdapter adapter = viewPager.getAdapter();
-        if (adapter == null) {
-            throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
+    public void setupWithViewPager(@Nullable final ViewPager viewPager) {
+        if (mViewPager != null && mPageChangeListener != null) {
+            // If we've already been setup with a ViewPager, remove us from it
+            mViewPager.removeOnPageChangeListener(mPageChangeListener);
         }
 
-        // First we'll add Tabs, using the adapter's page titles
-        setTabsFromPagerAdapter(adapter);
-
-        // Now we'll add our page change listener to the ViewPager
-        viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(this));
-
-        // Now we'll add a tab selected listener to set ViewPager's current item
-        setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
-
-        // Make sure we reflect the currently set ViewPager item
-        if (adapter.getCount() > 0) {
-            final int curItem = viewPager.getCurrentItem();
-            if (getSelectedTabPosition() != curItem) {
-                selectTab(getTabAt(curItem));
+        if (viewPager != null) {
+            final PagerAdapter adapter = viewPager.getAdapter();
+            if (adapter == null) {
+                throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
             }
+
+            mViewPager = viewPager;
+
+            // Add our custom OnPageChangeListener to the ViewPager
+            if (mPageChangeListener == null) {
+                mPageChangeListener = new TabLayoutOnPageChangeListener(this);
+            }
+            mPageChangeListener.reset();
+            viewPager.addOnPageChangeListener(mPageChangeListener);
+
+            // Now we'll add a tab selected listener to set ViewPager's current item
+            setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
+
+            // Now we'll populate ourselves from the pager adapter
+            setPagerAdapter(adapter, true);
+        } else {
+            // We've been given a null ViewPager so we need to clear out the internal state,
+            // listeners and observers
+            mViewPager = null;
+            setOnTabSelectedListener(null);
+            setPagerAdapter(null, true);
         }
     }
 
     /**
-     * Populate our tab content from the given {@link PagerAdapter}.
-     * <p>
-     * Any existing tabs will be removed first. Each tab will have it's text set to the value
-     * returned from {@link PagerAdapter#getPageTitle(int)}
-     * </p>
-     *
-     * @param adapter the adapter to populate from
+     * @deprecated Use {@link #setupWithViewPager(ViewPager)} to link a TabLayout with a ViewPager
+     *             together. When that method is used, the TabLayout will be automatically updated
+     *             when the {@link PagerAdapter} is changed.
      */
-    public void setTabsFromPagerAdapter(@NonNull PagerAdapter adapter) {
+    @Deprecated
+    public void setTabsFromPagerAdapter(@Nullable final PagerAdapter adapter) {
+        setPagerAdapter(adapter, false);
+    }
+
+    private 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);
+        }
+
+        mPagerAdapter = adapter;
+
+        if (addObserver && adapter != null) {
+            // Register our observer on the new adapter
+            if (mPagerAdapterObserver == null) {
+                mPagerAdapterObserver = new PagerAdapterObserver();
+            }
+            adapter.registerDataSetObserver(mPagerAdapterObserver);
+        }
+
+        // Finally make sure we reflect the new adapter
+        populateFromPagerAdapter();
+    }
+
+    private void populateFromPagerAdapter() {
         removeAllTabs();
-        for (int i = 0, count = adapter.getCount(); i < count; i++) {
-            addTab(newTab().setText(adapter.getPageTitle(i)));
+
+        if (mPagerAdapter != null) {
+            final int adapterCount = mPagerAdapter.getCount();
+            for (int i = 0; i < adapterCount; i++) {
+                addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
+            }
+
+            // Make sure we reflect the currently set ViewPager item
+            if (mViewPager != null && adapterCount > 0) {
+                final int curItem = mViewPager.getCurrentItem();
+                if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
+                    selectTab(getTabAt(curItem));
+                }
+            }
+        } else {
+            removeAllTabs();
         }
     }
 
@@ -631,9 +719,14 @@
         }
     }
 
-    private TabView createTabView(Tab tab) {
-        final TabView tabView = new TabView(getContext(), tab);
+    private TabView createTabView(@NonNull final Tab tab) {
+        TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;
+        if (tabView == null) {
+            tabView = new TabView(getContext());
+        }
+        tabView.setTab(tab);
         tabView.setFocusable(true);
+        tabView.setMinimumWidth(getTabMinWidth());
 
         if (mTabClickListener == null) {
             mTabClickListener = new View.OnClickListener() {
@@ -659,12 +752,16 @@
     }
 
     private void updateTab(int position) {
-        final TabView view = (TabView) mTabStrip.getChildAt(position);
+        final TabView view = getTabView(position);
         if (view != null) {
             view.update();
         }
     }
 
+    private TabView getTabView(int position) {
+        return (TabView) mTabStrip.getChildAt(position);
+    }
+
     private void addTabView(Tab tab, boolean setSelected) {
         final TabView tabView = createTabView(tab);
         mTabStrip.addView(tabView, createLayoutParamsForTabs());
@@ -706,7 +803,7 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // If we have a MeasureSpec which allows us to decide our height, try and use the default
         // height
-        final int idealHeight = dpToPx(DEFAULT_HEIGHT) + getPaddingTop() + getPaddingBottom();
+        final int idealHeight = dpToPx(getDefaultHeight()) + getPaddingTop() + getPaddingBottom();
         switch (MeasureSpec.getMode(heightMeasureSpec)) {
             case MeasureSpec.AT_MOST:
                 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -718,43 +815,54 @@
                 break;
         }
 
+        final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
+        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
+            // If we don't have an unspecified width spec, use the given size to calculate
+            // the max tab width
+            mTabMaxWidth = mRequestedTabMaxWidth > 0
+                    ? mRequestedTabMaxWidth
+                    : specWidth - dpToPx(TAB_MIN_WIDTH_MARGIN);
+        }
+
         // Now super measure itself using the (possibly) modified height spec
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        if (mMode == MODE_FIXED && getChildCount() == 1) {
+        if (getChildCount() == 1) {
             // If we're in fixed mode then we need to make the tab strip is the same width as us
             // so we don't scroll
             final View child = getChildAt(0);
-            final int width = getMeasuredWidth();
+            boolean remeasure = false;
 
-            if (child.getMeasuredWidth() > width) {
-                // If the child is wider than us, re-measure it with a widthSpec set to exact our
-                // measure width
+            switch (mMode) {
+                case MODE_SCROLLABLE:
+                    // We only need to resize the child if it's smaller than us. This is similar
+                    // to fillViewport
+                    remeasure = child.getMeasuredWidth() < getMeasuredWidth();
+                    break;
+                case MODE_FIXED:
+                    // Resize the child so that it doesn't scroll
+                    remeasure = child.getMeasuredWidth() != getMeasuredWidth();
+                    break;
+            }
+
+            if (remeasure) {
+                // Re-measure the child with a widthSpec set to be exactly our measure width
                 int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTop()
                         + getPaddingBottom(), child.getLayoutParams().height);
-                int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+                int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        getMeasuredWidth(), MeasureSpec.EXACTLY);
                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
             }
         }
-
-        // Now update the tab max width. We do it here as the default tab min width is
-        // layout width - 56dp
-        int maxTabWidth = mRequestedTabMaxWidth;
-        final int defaultTabMaxWidth = getMeasuredWidth() - dpToPx(TAB_MIN_WIDTH_MARGIN);
-        if (maxTabWidth == 0 || maxTabWidth > defaultTabMaxWidth) {
-            // If the request tab max width is 0, or larger than our default, use the default
-            maxTabWidth = defaultTabMaxWidth;
-        }
-
-        if (mTabMaxWidth != maxTabWidth) {
-            // If the tab max width has changed, re-measure
-            mTabMaxWidth = maxTabWidth;
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
     }
 
     private void removeTabViewAt(int position) {
+        final TabView view = (TabView) mTabStrip.getChildAt(position);
         mTabStrip.removeViewAt(position);
+        if (view != null) {
+            view.reset();
+            mTabViewPool.release(view);
+        }
         requestLayout();
     }
 
@@ -818,9 +926,11 @@
                 animateToTab(tab.getPosition());
             }
         } else {
-            final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
-            setSelectedTabView(newPosition);
             if (updateIndicator) {
+                final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
+                if (newPosition != Tab.INVALID_POSITION) {
+                    setSelectedTabView(newPosition);
+                }
                 if ((mSelectedTab == null || mSelectedTab.getPosition() == Tab.INVALID_POSITION)
                         && newPosition != Tab.INVALID_POSITION) {
                     // If we don't currently have a tab, just draw the indicator
@@ -873,14 +983,17 @@
                 break;
         }
 
-        updateTabViewsLayoutParams();
+        updateTabViews(true);
     }
 
-    private void updateTabViewsLayoutParams() {
+    private void updateTabViews(final boolean requestLayout) {
         for (int i = 0; i < mTabStrip.getChildCount(); i++) {
             View child = mTabStrip.getChildAt(i);
+            child.setMinimumWidth(getTabMinWidth());
             updateTabViewLayoutParams((LinearLayout.LayoutParams) child.getLayoutParams());
-            child.requestLayout();
+            if (requestLayout) {
+                child.requestLayout();
+            }
         }
     }
 
@@ -973,13 +1086,14 @@
          * the value given to {@link #setIcon(Drawable)}.
          * </p>
          *
-         * @param layoutResId A layout resource to inflate and use as a custom tab view
+         * @param resId A layout resource to inflate and use as a custom tab view
          * @return The current instance for call chaining
          */
         @NonNull
-        public Tab setCustomView(@LayoutRes int layoutResId) {
-            return setCustomView(
-                    LayoutInflater.from(mParent.getContext()).inflate(layoutResId, null));
+        public Tab setCustomView(@LayoutRes int resId) {
+            final TabView tabView = mParent.getTabView(mPosition);
+            final LayoutInflater inflater = LayoutInflater.from(tabView.getContext());
+            return setCustomView(inflater.inflate(resId, tabView, false));
         }
 
         /**
@@ -1039,7 +1153,7 @@
          */
         @NonNull
         public Tab setIcon(@DrawableRes int resId) {
-            return setIcon(TintManager.getDrawable(mParent.getContext(), resId));
+            return setIcon(AppCompatDrawableManager.get().getDrawable(mParent.getContext(), resId));
         }
 
         /**
@@ -1127,10 +1241,19 @@
         public CharSequence getContentDescription() {
             return mContentDesc;
         }
+
+        private void reset() {
+            mTag = null;
+            mIcon = null;
+            mText = null;
+            mContentDesc = null;
+            mPosition = INVALID_POSITION;
+            mCustomView = null;
+        }
     }
 
     class TabView extends LinearLayout implements OnLongClickListener {
-        private final Tab mTab;
+        private Tab mTab;
         private TextView mTextView;
         private ImageView mIconView;
 
@@ -1138,16 +1261,18 @@
         private TextView mCustomTextView;
         private ImageView mCustomIconView;
 
-        public TabView(Context context, Tab tab) {
+        private int mDefaultMaxLines = 2;
+
+        public TabView(Context context) {
             super(context);
-            mTab = tab;
             if (mTabBackgroundResId != 0) {
-                setBackgroundDrawable(TintManager.getDrawable(context, mTabBackgroundResId));
+                setBackgroundDrawable(
+                        AppCompatDrawableManager.get().getDrawable(context, mTabBackgroundResId));
             }
             ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
                     mTabPaddingEnd, mTabPaddingBottom);
             setGravity(Gravity.CENTER);
-            update();
+            setOrientation(VERTICAL);
         }
 
         @Override
@@ -1183,22 +1308,85 @@
         }
 
         @Override
-        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        public void onMeasure(final int origWidthMeasureSpec, final int origHeightMeasureSpec) {
+            final int specWidthSize = MeasureSpec.getSize(origWidthMeasureSpec);
+            final int specWidthMode = MeasureSpec.getMode(origWidthMeasureSpec);
+            final int maxWidth = getTabMaxWidth();
+
+            final int widthMeasureSpec;
+            final int heightMeasureSpec = origHeightMeasureSpec;
+
+            if (maxWidth > 0 && (specWidthMode == MeasureSpec.UNSPECIFIED
+                    || specWidthSize > maxWidth)) {
+                // If we have a max width and a given spec which is either unspecified or
+                // larger than the max width, update the width spec using the same mode
+                widthMeasureSpec = MeasureSpec.makeMeasureSpec(mTabMaxWidth, specWidthMode);
+            } else {
+                // Else, use the original width spec
+                widthMeasureSpec = origWidthMeasureSpec;
+            }
+
+            // Now lets measure
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-            final int measuredWidth = getMeasuredWidth();
-            if (measuredWidth < mTabMinWidth || measuredWidth > mTabMaxWidth) {
-                // Re-measure if we are outside our min or max width
-                widthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        MathUtils.constrain(measuredWidth, mTabMinWidth, mTabMaxWidth),
-                        MeasureSpec.EXACTLY);
-                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            // We need to switch the text size based on whether the text is spanning 2 lines or not
+            if (mTextView != null) {
+                final Resources res = getResources();
+                float textSize = mTabTextSize;
+                int maxLines = mDefaultMaxLines;
+
+                if (mIconView != null && mIconView.getVisibility() == VISIBLE) {
+                    // If the icon view is being displayed, we limit the text to 1 line
+                    maxLines = 1;
+                } else if (mTextView != null && mTextView.getLineCount() > 1) {
+                    // Otherwise when we have text which wraps we reduce the text size
+                    textSize = mTabTextMultiLineSize;
+                }
+
+                final float curTextSize = mTextView.getTextSize();
+                final int curLineCount = mTextView.getLineCount();
+                final int curMaxLines = TextViewCompat.getMaxLines(mTextView);
+
+                if (textSize != curTextSize || (curMaxLines >= 0 && maxLines != curMaxLines)) {
+                    // We've got a new text size and/or max lines...
+                    boolean updateTextView = true;
+
+                    if (mMode == MODE_FIXED && textSize > curTextSize && curLineCount == 1) {
+                        // If we're in fixed mode, going up in text size and currently have 1 line
+                        // then it's very easy to get into an infinite recursion.
+                        // To combat that we check to see if the change in text size
+                        // will cause a line count change. If so, abort the size change.
+                        final Layout layout = mTextView.getLayout();
+                        if (layout == null
+                                || approximateLineWidth(layout, 0, textSize) > layout.getWidth()) {
+                            updateTextView = false;
+                        }
+                    }
+
+                    if (updateTextView) {
+                        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+                        mTextView.setMaxLines(maxLines);
+                        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+                    }
+                }
             }
         }
 
+        private void setTab(@Nullable final Tab tab) {
+            if (tab != mTab) {
+                mTab = tab;
+                update();
+            }
+        }
+
+        private void reset() {
+            setTab(null);
+            setSelected(false);
+        }
+
         final void update() {
             final Tab tab = mTab;
-            final View custom = tab.getCustomView();
+            final View custom = tab != null ? tab.getCustomView() : null;
             if (custom != null) {
                 final ViewParent customParent = custom.getParent();
                 if (customParent != this) {
@@ -1217,6 +1405,9 @@
                 }
 
                 mCustomTextView = (TextView) custom.findViewById(android.R.id.text1);
+                if (mCustomTextView != null) {
+                    mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);
+                }
                 mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);
             } else {
                 // We do not have a custom view. Remove one if it already exists
@@ -1241,23 +1432,26 @@
                             .inflate(R.layout.design_layout_tab_text, this, false);
                     addView(textView);
                     mTextView = textView;
+                    mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
                 }
                 mTextView.setTextAppearance(getContext(), mTabTextAppearance);
                 if (mTabTextColors != null) {
                     mTextView.setTextColor(mTabTextColors);
                 }
-                updateTextAndIcon(tab, mTextView, mIconView);
+                updateTextAndIcon(mTextView, mIconView);
             } else {
                 // Else, we'll see if there is a TextView or ImageView present and update them
                 if (mCustomTextView != null || mCustomIconView != null) {
-                    updateTextAndIcon(tab, mCustomTextView, mCustomIconView);
+                    updateTextAndIcon(mCustomTextView, mCustomIconView);
                 }
             }
         }
 
-        private void updateTextAndIcon(Tab tab, TextView textView, ImageView iconView) {
-            final Drawable icon = tab.getIcon();
-            final CharSequence text = tab.getText();
+        private void updateTextAndIcon(@Nullable final TextView textView,
+                @Nullable final ImageView iconView) {
+            final Drawable icon = mTab != null ? mTab.getIcon() : null;
+            final CharSequence text = mTab != null ? mTab.getText() : null;
+            final CharSequence contentDesc = mTab != null ? mTab.getContentDescription() : null;
 
             if (iconView != null) {
                 if (icon != null) {
@@ -1268,23 +1462,36 @@
                     iconView.setVisibility(GONE);
                     iconView.setImageDrawable(null);
                 }
-                iconView.setContentDescription(tab.getContentDescription());
+                iconView.setContentDescription(contentDesc);
             }
 
             final boolean hasText = !TextUtils.isEmpty(text);
             if (textView != null) {
                 if (hasText) {
                     textView.setText(text);
-                    textView.setContentDescription(tab.getContentDescription());
                     textView.setVisibility(VISIBLE);
                     setVisibility(VISIBLE);
                 } else {
                     textView.setVisibility(GONE);
                     textView.setText(null);
                 }
+                textView.setContentDescription(contentDesc);
             }
 
-            if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
+            if (iconView != null) {
+                MarginLayoutParams lp = ((MarginLayoutParams) iconView.getLayoutParams());
+                int bottomMargin = 0;
+                if (hasText && iconView.getVisibility() == VISIBLE) {
+                    // If we're showing both text and icon, add some margin bottom to the icon
+                    bottomMargin = dpToPx(DEFAULT_GAP_TEXT_ICON);
+                }
+                if (bottomMargin != lp.bottomMargin) {
+                    lp.bottomMargin = bottomMargin;
+                    iconView.requestLayout();
+                }
+            }
+
+            if (!hasText && !TextUtils.isEmpty(contentDesc)) {
                 setOnLongClickListener(this);
             } else {
                 setOnLongClickListener(null);
@@ -1315,6 +1522,13 @@
         public Tab getTab() {
             return mTab;
         }
+
+        /**
+         * Approximates a given lines width with the new provided text size.
+         */
+        private float approximateLineWidth(Layout layout, int line, float textSize) {
+            return layout.getLineWidth(line) * (textSize / layout.getPaint().getTextSize());
+        }
     }
 
     private class SlidingTabStrip extends LinearLayout {
@@ -1327,6 +1541,8 @@
         private int mIndicatorLeft = -1;
         private int mIndicatorRight = -1;
 
+        private ValueAnimatorCompat mIndicatorAnimator;
+
         SlidingTabStrip(Context context) {
             super(context);
             setWillNotDraw(false);
@@ -1358,6 +1574,10 @@
         }
 
         void setIndicatorPositionFromTabPosition(int position, float positionOffset) {
+            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
+                mIndicatorAnimator.cancel();
+            }
+
             mSelectedPosition = position;
             mSelectionOffset = positionOffset;
             updateIndicatorPosition();
@@ -1380,14 +1600,13 @@
             if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {
                 final int count = getChildCount();
 
-                final int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
-                // First we'll find the largest tab
+                // First we'll find the widest tab
                 int largestTabWidth = 0;
                 for (int i = 0, z = count; i < z; i++) {
-                    final View child = getChildAt(i);
-                    child.measure(unspecifiedSpec, heightMeasureSpec);
-                    largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
+                    View child = getChildAt(i);
+                    if (child.getVisibility() == VISIBLE) {
+                        largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
+                    }
                 }
 
                 if (largestTabWidth <= 0) {
@@ -1396,32 +1615,50 @@
                 }
 
                 final int gutter = dpToPx(FIXED_WRAP_GUTTER_MIN);
+                boolean remeasure = false;
+
                 if (largestTabWidth * count <= getMeasuredWidth() - gutter * 2) {
                     // If the tabs fit within our width minus gutters, we will set all tabs to have
                     // the same width
                     for (int i = 0; i < count; i++) {
-                        final View child = getChildAt(i);
-                        final LinearLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                        lp.width = largestTabWidth;
-                        lp.weight = 0;
+                        final LinearLayout.LayoutParams lp =
+                                (LayoutParams) getChildAt(i).getLayoutParams();
+                        if (lp.width != largestTabWidth || lp.weight != 0) {
+                            lp.width = largestTabWidth;
+                            lp.weight = 0;
+                            remeasure = true;
+                        }
                     }
                 } else {
                     // If the tabs will wrap to be larger than the width minus gutters, we need
                     // to switch to GRAVITY_FILL
                     mTabGravity = GRAVITY_FILL;
-                    updateTabViewsLayoutParams();
+                    updateTabViews(false);
+                    remeasure = true;
                 }
 
-                // Now re-measure after our changes
-                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+                if (remeasure) {
+                    // Now re-measure after our changes
+                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+                }
             }
         }
 
         @Override
         protected void onLayout(boolean changed, int l, int t, int r, int b) {
             super.onLayout(changed, l, t, r, b);
-            // If we've been layed out, update the indicator position
-            updateIndicatorPosition();
+
+            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
+                // If we're currently running an animation, lets cancel it and start a
+                // new animation with the remaining duration
+                mIndicatorAnimator.cancel();
+                final long duration = mIndicatorAnimator.getDuration();
+                animateIndicatorToPosition(mSelectedPosition,
+                        Math.round((1f - mIndicatorAnimator.getAnimatedFraction()) * duration));
+            } else {
+                // If we've been layed out, update the indicator position
+                updateIndicatorPosition();
+            }
         }
 
         private void updateIndicatorPosition() {
@@ -1457,6 +1694,10 @@
         }
 
         void animateIndicatorToPosition(final int position, int duration) {
+            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
+                mIndicatorAnimator.cancel();
+            }
+
             final boolean isRtl = ViewCompat.getLayoutDirection(this)
                     == ViewCompat.LAYOUT_DIRECTION_RTL;
 
@@ -1510,12 +1751,6 @@
                         mSelectedPosition = position;
                         mSelectionOffset = 0f;
                     }
-
-                    @Override
-                    public void onAnimationCancel(ValueAnimatorCompat animator) {
-                        mSelectedPosition = position;
-                        mSelectionOffset = 0f;
-                    }
                 });
                 animator.start();
             }
@@ -1550,14 +1785,29 @@
         return new ColorStateList(states, colors);
     }
 
-    private ColorStateList loadTextColorFromTextAppearance(int textAppearanceResId) {
-        TypedArray a = getContext().obtainStyledAttributes(textAppearanceResId,
-                R.styleable.TextAppearance);
-        try {
-            return a.getColorStateList(R.styleable.TextAppearance_android_textColor);
-        } finally {
-            a.recycle();
+    private int getDefaultHeight() {
+        boolean hasIconAndText = false;
+        for (int i = 0, count = mTabs.size(); i < count; i++) {
+            Tab tab = mTabs.get(i);
+            if (tab != null && tab.getIcon() != null && !TextUtils.isEmpty(tab.getText())) {
+                hasIconAndText = true;
+                break;
+            }
         }
+        return hasIconAndText ? DEFAULT_HEIGHT_WITH_TEXT_ICON : DEFAULT_HEIGHT;
+    }
+
+    private int getTabMinWidth() {
+        if (mRequestedTabMinWidth != INVALID_WIDTH) {
+            // If we have been given a min width, use it
+            return mRequestedTabMinWidth;
+        }
+        // Else, we'll use the default value
+        return mMode == MODE_SCROLLABLE ? mScrollableTabMinWidth : 0;
+    }
+
+    private int getTabMaxWidth() {
+        return mTabMaxWidth;
     }
 
     /**
@@ -1590,25 +1840,35 @@
                 int positionOffsetPixels) {
             final TabLayout tabLayout = mTabLayoutRef.get();
             if (tabLayout != null) {
-                // Update the scroll position, only update the text selection if we're being
-                // dragged (or we're settling after a drag)
-                final boolean updateText = (mScrollState == ViewPager.SCROLL_STATE_DRAGGING)
-                        || (mScrollState == ViewPager.SCROLL_STATE_SETTLING
-                        && mPreviousScrollState == ViewPager.SCROLL_STATE_DRAGGING);
-                tabLayout.setScrollPosition(position, positionOffset, updateText);
+                // Only update the text selection if we're not settling, or we are settling after
+                // being dragged
+                final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
+                        mPreviousScrollState == SCROLL_STATE_DRAGGING;
+                // Update the indicator if we're not settling after being idle. This is caused
+                // from a setCurrentItem() call and will be handled by an animation from
+                // onPageSelected() instead.
+                final boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
+                        && mPreviousScrollState == SCROLL_STATE_IDLE);
+                tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
             }
         }
 
         @Override
         public void onPageSelected(int position) {
             final TabLayout tabLayout = mTabLayoutRef.get();
-            if (tabLayout != null) {
+            if (tabLayout != null && tabLayout.getSelectedTabPosition() != position) {
                 // Select the tab, only updating the indicator if we're not being dragged/settled
                 // (since onPageScrolled will handle that).
-                tabLayout.selectTab(tabLayout.getTabAt(position),
-                        mScrollState == ViewPager.SCROLL_STATE_IDLE);
+                final boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE
+                        || (mScrollState == SCROLL_STATE_SETTLING
+                        && mPreviousScrollState == SCROLL_STATE_IDLE);
+                tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
             }
         }
+
+        private void reset() {
+            mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
+        }
     }
 
     /**
@@ -1638,4 +1898,16 @@
         }
     }
 
+    private class PagerAdapterObserver extends DataSetObserver {
+        @Override
+        public void onChanged() {
+            populateFromPagerAdapter();
+        }
+
+        @Override
+        public void onInvalidated() {
+            populateFromPagerAdapter();
+        }
+    }
+
 }
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 16ebc30..32abe85 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -22,7 +22,11 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
 import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.StyleRes;
 import android.support.design.R;
@@ -31,7 +35,8 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v4.widget.Space;
+import android.support.v7.widget.AppCompatDrawableManager;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -56,15 +61,29 @@
 public class TextInputLayout extends LinearLayout {
 
     private static final int ANIMATION_DURATION = 200;
+    private static final int INVALID_MAX_LENGTH = -1;
 
     private EditText mEditText;
+
+    private boolean mHintEnabled;
     private CharSequence mHint;
 
     private Paint mTmpPaint;
 
+    private LinearLayout mIndicatorArea;
+    private int mIndicatorsAdded;
+
     private boolean mErrorEnabled;
     private TextView mErrorView;
     private int mErrorTextAppearance;
+    private boolean mErrorShown;
+
+    private boolean mCounterEnabled;
+    private TextView mCounterView;
+    private int mCounterMaxLength;
+    private int mCounterTextAppearance;
+    private int mCounterOverflowTextAppearance;
+    private boolean mCounterOverflowed;
 
     private ColorStateList mDefaultTextColor;
     private ColorStateList mFocusedTextColor;
@@ -74,6 +93,8 @@
     private boolean mHintAnimationEnabled;
     private ValueAnimatorCompat mAnimator;
 
+    private boolean mHasReconstructedEditTextBackground;
+
     public TextInputLayout(Context context) {
         this(context, null);
     }
@@ -86,6 +107,8 @@
         // Can't call through to super(Context, AttributeSet, int) since it doesn't exist on API 10
         super(context, attrs);
 
+        ThemeUtils.checkAppCompatTheme(context);
+
         setOrientation(VERTICAL);
         setWillNotDraw(false);
         setAddStatesFromChildren(true);
@@ -96,7 +119,8 @@
 
         final TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.TextInputLayout, defStyleAttr, R.style.Widget_Design_TextInputLayout);
-        mHint = a.getText(R.styleable.TextInputLayout_android_hint);
+        mHintEnabled = a.getBoolean(R.styleable.TextInputLayout_hintEnabled, true);
+        setHint(a.getText(R.styleable.TextInputLayout_android_hint));
         mHintAnimationEnabled = a.getBoolean(
                 R.styleable.TextInputLayout_hintAnimationEnabled, true);
 
@@ -114,9 +138,19 @@
 
         mErrorTextAppearance = a.getResourceId(R.styleable.TextInputLayout_errorTextAppearance, 0);
         final boolean errorEnabled = a.getBoolean(R.styleable.TextInputLayout_errorEnabled, false);
+
+        final boolean counterEnabled = a.getBoolean(
+                R.styleable.TextInputLayout_counterEnabled, false);
+        setCounterMaxLength(
+                a.getInt(R.styleable.TextInputLayout_counterMaxLength, INVALID_MAX_LENGTH));
+        mCounterTextAppearance = a.getResourceId(
+                R.styleable.TextInputLayout_counterTextAppearance, 0);
+        mCounterOverflowTextAppearance = a.getResourceId(
+                R.styleable.TextInputLayout_counterOverflowTextAppearance, 0);
         a.recycle();
 
         setErrorEnabled(errorEnabled);
+        setCounterEnabled(counterEnabled);
 
         if (ViewCompat.getImportantForAccessibility(this)
                 == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
@@ -140,12 +174,21 @@
     }
 
     /**
-     * Set the typeface to use for the both the expanded and floating hint.
+     * Set the typeface to use for both the expanded and floating hint.
      *
      * @param typeface typeface to use, or {@code null} to use the default.
      */
     public void setTypeface(@Nullable Typeface typeface) {
-        mCollapsingTextHelper.setTypeface(typeface);
+        mCollapsingTextHelper.setTypefaces(typeface);
+    }
+
+    /**
+     * Returns the typeface used for both the expanded and floating hint.
+     */
+    @NonNull
+    public Typeface getTypeface() {
+        // This could be either the collapsed or expanded
+        return mCollapsingTextHelper.getCollapsedTypeface();
     }
 
     private void setEditText(EditText editText) {
@@ -156,7 +199,7 @@
         mEditText = editText;
 
         // Use the EditText's typeface, and it's text size for our expanded text
-        mCollapsingTextHelper.setTypeface(mEditText.getTypeface());
+        mCollapsingTextHelper.setTypefaces(mEditText.getTypeface());
         mCollapsingTextHelper.setExpandedTextSize(mEditText.getTextSize());
         mCollapsingTextHelper.setExpandedTextGravity(mEditText.getGravity());
 
@@ -164,7 +207,10 @@
         mEditText.addTextChangedListener(new TextWatcher() {
             @Override
             public void afterTextChanged(Editable s) {
-                updateLabelVisibility(true);
+                updateLabelState(true);
+                if (mCounterEnabled) {
+                    updateCounter(s.length());
+                }
             }
 
             @Override
@@ -179,21 +225,23 @@
             mDefaultTextColor = mEditText.getHintTextColors();
         }
 
-        // If we do not have a valid hint, try and retrieve it from the EditText
-        if (TextUtils.isEmpty(mHint)) {
+        // If we do not have a valid hint, try and retrieve it from the EditText, if enabled
+        if (mHintEnabled && TextUtils.isEmpty(mHint)) {
             setHint(mEditText.getHint());
             // Clear the EditText's hint as we will display it ourselves
             mEditText.setHint(null);
         }
 
-        if (mErrorView != null) {
-            // Add some start/end padding to the error so that it matches the EditText
-            ViewCompat.setPaddingRelative(mErrorView, ViewCompat.getPaddingStart(mEditText),
-                    0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
+        if (mCounterView != null) {
+            updateCounter(mEditText.getText().length());
+        }
+
+        if (mIndicatorArea != null) {
+            adjustIndicatorPadding();
         }
 
         // Update the label visibility with no animation
-        updateLabelVisibility(false);
+        updateLabelState(false);
     }
 
     private LayoutParams updateEditTextMargin(ViewGroup.LayoutParams lp) {
@@ -201,28 +249,40 @@
         // to the EditText so make room for the label
         LayoutParams llp = lp instanceof LayoutParams ? (LayoutParams) lp : new LayoutParams(lp);
 
-        if (mTmpPaint == null) {
-            mTmpPaint = new Paint();
+        if (mHintEnabled) {
+            if (mTmpPaint == null) {
+                mTmpPaint = new Paint();
+            }
+            mTmpPaint.setTypeface(mCollapsingTextHelper.getCollapsedTypeface());
+            mTmpPaint.setTextSize(mCollapsingTextHelper.getCollapsedTextSize());
+            llp.topMargin = (int) -mTmpPaint.ascent();
+        } else {
+            llp.topMargin = 0;
         }
-        mTmpPaint.setTypeface(mCollapsingTextHelper.getTypeface());
-        mTmpPaint.setTextSize(mCollapsingTextHelper.getCollapsedTextSize());
-        llp.topMargin = (int) -mTmpPaint.ascent();
 
         return llp;
     }
 
-    private void updateLabelVisibility(boolean animate) {
-        boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
-        boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
+    private void updateLabelState(boolean animate) {
+        final boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
+        final boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
+        final boolean isErrorShowing = !TextUtils.isEmpty(getError());
 
-        if (mDefaultTextColor != null && mFocusedTextColor != null) {
+        if (mDefaultTextColor != null) {
             mCollapsingTextHelper.setExpandedTextColor(mDefaultTextColor.getDefaultColor());
-            mCollapsingTextHelper.setCollapsedTextColor(isFocused
-                    ? mFocusedTextColor.getDefaultColor()
-                    : mDefaultTextColor.getDefaultColor());
         }
 
-        if (hasText || isFocused) {
+        if (mCounterOverflowed && mCounterView != null) {
+            mCollapsingTextHelper.setCollapsedTextColor(mCounterView.getCurrentTextColor());
+        } else if (isErrorShowing && mErrorView != null) {
+            mCollapsingTextHelper.setCollapsedTextColor(mErrorView.getCurrentTextColor());
+        } else if (isFocused && mFocusedTextColor != null) {
+            mCollapsingTextHelper.setCollapsedTextColor(mFocusedTextColor.getDefaultColor());
+        } else if (mDefaultTextColor != null) {
+            mCollapsingTextHelper.setCollapsedTextColor(mDefaultTextColor.getDefaultColor());
+        }
+
+        if (hasText || isFocused || isErrorShowing) {
             // We should be showing the label so do so if it isn't already
             collapseHint(animate);
         } else {
@@ -240,25 +300,89 @@
     }
 
     /**
-     * Set the hint to be displayed in the floating label
+     * Set the hint to be displayed in the floating label, if enabled.
+     *
+     * @see #setHintEnabled(boolean)
      *
      * @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
      */
     public void setHint(@Nullable CharSequence hint) {
+        if (mHintEnabled) {
+            setHintInternal(hint);
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        }
+    }
+
+    private void setHintInternal(CharSequence hint) {
         mHint = hint;
         mCollapsingTextHelper.setText(hint);
-
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
     }
 
     /**
-     * Returns the hint which is displayed in the floating label.
+     * Returns the hint which is displayed in the floating label, if enabled.
+     *
+     * @return the hint, or null if there isn't one set, or the hint is not enabled.
      *
      * @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
      */
     @Nullable
     public CharSequence getHint() {
-        return mHint;
+        return mHintEnabled ? mHint : null;
+    }
+
+    /**
+     * Sets whether the floating label functionality is enabled or not in this layout.
+     *
+     * <p>If enabled, any non-empty hint in the child EditText will be moved into the floating
+     * hint, and its existing hint will be cleared. If disabled, then any non-empty floating hint
+     * in this layout will be moved into the EditText, and this layout's hint will be cleared.</p>
+     *
+     * @see #setHint(CharSequence)
+     * @see #isHintEnabled()
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
+     */
+    public void setHintEnabled(boolean enabled) {
+        if (enabled != mHintEnabled) {
+            mHintEnabled = enabled;
+
+            final CharSequence editTextHint = mEditText.getHint();
+            if (!mHintEnabled) {
+                if (!TextUtils.isEmpty(mHint) && TextUtils.isEmpty(editTextHint)) {
+                    // If the hint is disabled, but we have a hint set, and the EditText doesn't,
+                    // pass it through...
+                    mEditText.setHint(mHint);
+                }
+                // Now clear out any set hint
+                setHintInternal(null);
+            } else {
+                if (!TextUtils.isEmpty(editTextHint)) {
+                    // If the hint is now enabled and the EditText has one set, we'll use it if
+                    // we don't already have one, and clear the EditText's
+                    if (TextUtils.isEmpty(mHint)) {
+                        setHint(editTextHint);
+                    }
+                    mEditText.setHint(null);
+                }
+            }
+
+            // Now update the EditText top margin
+            if (mEditText != null) {
+                final LayoutParams lp = updateEditTextMargin(mEditText.getLayoutParams());
+                mEditText.setLayoutParams(lp);
+            }
+        }
+    }
+
+    /**
+     * Returns whether the floating label functionality is enabled or not in this layout.
+     *
+     * @see #setHintEnabled(boolean)
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
+     */
+    public boolean isHintEnabled() {
+        return mHintEnabled;
     }
 
     /**
@@ -271,7 +395,7 @@
         mFocusedTextColor = ColorStateList.valueOf(mCollapsingTextHelper.getCollapsedTextColor());
 
         if (mEditText != null) {
-            updateLabelVisibility(false);
+            updateLabelState(false);
 
             // Text size might have changed so update the top margin
             LayoutParams lp = updateEditTextMargin(mEditText.getLayoutParams());
@@ -280,6 +404,42 @@
         }
     }
 
+    private void addIndicator(TextView indicator, int index) {
+        if (mIndicatorArea == null) {
+            mIndicatorArea = new LinearLayout(getContext());
+            mIndicatorArea.setOrientation(LinearLayout.HORIZONTAL);
+            addView(mIndicatorArea, LinearLayout.LayoutParams.MATCH_PARENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT);
+
+            // Add a flexible spacer in the middle so that the left/right views stay pinned
+            final Space spacer = new Space(getContext());
+            final LinearLayout.LayoutParams spacerLp = new LinearLayout.LayoutParams(0, 0, 1f);
+            mIndicatorArea.addView(spacer, spacerLp);
+
+            if (mEditText != null) {
+                adjustIndicatorPadding();
+            }
+        }
+        mIndicatorArea.setVisibility(View.VISIBLE);
+        mIndicatorArea.addView(indicator, index);
+        mIndicatorsAdded++;
+    }
+
+    private void adjustIndicatorPadding() {
+        // Add padding to the error and character counter so that they match the EditText
+        ViewCompat.setPaddingRelative(mIndicatorArea, ViewCompat.getPaddingStart(mEditText),
+                0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
+    }
+
+    private void removeIndicator(TextView indicator) {
+        if (mIndicatorArea != null) {
+            mIndicatorArea.removeView(indicator);
+            if (--mIndicatorsAdded == 0) {
+                mIndicatorArea.setVisibility(View.GONE);
+            }
+        }
+    }
+
     /**
      * Whether the error functionality is enabled or not in this layout. Enabling this
      * functionality before setting an error message via {@link #setError(CharSequence)}, will mean
@@ -297,15 +457,13 @@
                 mErrorView = new TextView(getContext());
                 mErrorView.setTextAppearance(getContext(), mErrorTextAppearance);
                 mErrorView.setVisibility(INVISIBLE);
-                addView(mErrorView);
-
-                if (mEditText != null) {
-                    // Add some start/end padding to the error so that it matches the EditText
-                    ViewCompat.setPaddingRelative(mErrorView, ViewCompat.getPaddingStart(mEditText),
-                            0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
-                }
+                ViewCompat.setAccessibilityLiveRegion(mErrorView,
+                        ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
+                addIndicator(mErrorView, 0);
             } else {
-                removeView(mErrorView);
+                mErrorShown = false;
+                updateEditTextBackground();
+                removeIndicator(mErrorView);
                 mErrorView = null;
             }
             mErrorEnabled = enabled;
@@ -345,44 +503,202 @@
         }
 
         if (!TextUtils.isEmpty(error)) {
-            ViewCompat.setAlpha(mErrorView, 0f);
-            mErrorView.setText(error);
-            ViewCompat.animate(mErrorView)
-                    .alpha(1f)
-                    .setDuration(ANIMATION_DURATION)
-                    .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                    .setListener(new ViewPropertyAnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationStart(View view) {
-                            view.setVisibility(VISIBLE);
-                        }
-                    })
-                    .start();
+            boolean animate;
+            if (TextUtils.equals(error, mErrorView.getText())) {
+                // We've been given the same error message, so only animate if needed
+                animate = !mErrorView.isShown() || ViewCompat.getAlpha(mErrorView) < 1f;
+            } else {
+                animate = true;
+                mErrorView.setText(error);
+            }
+
+            if (animate) {
+                if (ViewCompat.getAlpha(mErrorView) == 1f) {
+                    // If it's currently 100% show, we'll animate it from 0
+                    ViewCompat.setAlpha(mErrorView, 0f);
+                }
+                ViewCompat.animate(mErrorView)
+                        .alpha(1f)
+                        .setDuration(ANIMATION_DURATION)
+                        .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
+                        .setListener(new ViewPropertyAnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationStart(View view) {
+                                view.setVisibility(VISIBLE);
+                            }
+                        })
+                        .start();
+            }
 
             // Set the EditText's background tint to the error color
-            ViewCompat.setBackgroundTintList(mEditText,
-                    ColorStateList.valueOf(mErrorView.getCurrentTextColor()));
+            mErrorShown = true;
+            updateEditTextBackground();
+            updateLabelState(true);
         } else {
             if (mErrorView.getVisibility() == VISIBLE) {
                 ViewCompat.animate(mErrorView)
                         .alpha(0f)
                         .setDuration(ANIMATION_DURATION)
-                        .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
+                        .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
                         .setListener(new ViewPropertyAnimatorListenerAdapter() {
                             @Override
                             public void onAnimationEnd(View view) {
                                 view.setVisibility(INVISIBLE);
+
+                                updateLabelState(true);
                             }
                         }).start();
 
                 // Restore the 'original' tint, using colorControlNormal and colorControlActivated
-                final TintManager tintManager = TintManager.get(getContext());
-                ViewCompat.setBackgroundTintList(mEditText,
-                        tintManager.getTintList(R.drawable.abc_edit_text_material));
+                mErrorShown = false;
+                updateEditTextBackground();
             }
         }
+    }
 
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+    /**
+     * Whether the character counter functionality is enabled or not in this layout.
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_counterEnabled
+     */
+    public void setCounterEnabled(boolean enabled) {
+        if (mCounterEnabled != enabled) {
+            if (enabled) {
+                mCounterView = new TextView(getContext());
+                mCounterView.setMaxLines(1);
+                mCounterView.setTextAppearance(getContext(), mCounterTextAppearance);
+                ViewCompat.setAccessibilityLiveRegion(mCounterView,
+                        ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
+                addIndicator(mCounterView, -1);
+                if (mEditText == null) {
+                    updateCounter(0);
+                } else {
+                    updateCounter(mEditText.getText().length());
+                }
+            } else {
+                removeIndicator(mCounterView);
+                mCounterView = null;
+            }
+            mCounterEnabled = enabled;
+        }
+    }
+
+    /**
+     * Returns whether the character counter functionality is enabled or not in this layout.
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_counterEnabled
+     *
+     * @see #setCounterEnabled(boolean)
+     */
+    public boolean isCounterEnabled() {
+        return mCounterEnabled;
+    }
+
+    /**
+     * Sets the max length to display at the character counter.
+     *
+     * @param maxLength maxLength to display. Any value less than or equal to 0 will not be shown.
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_counterMaxLength
+     */
+    public void setCounterMaxLength(int maxLength) {
+        if (mCounterMaxLength != maxLength) {
+            if (maxLength > 0) {
+                mCounterMaxLength = maxLength;
+            } else {
+                mCounterMaxLength = INVALID_MAX_LENGTH;
+            }
+            if (mCounterEnabled) {
+                updateCounter(mEditText == null ? 0 : mEditText.getText().length());
+            }
+        }
+    }
+
+    /**
+     * Returns the max length shown at the character counter.
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_counterMaxLength
+     */
+    public int getCounterMaxLength() {
+        return mCounterMaxLength;
+    }
+
+    private void updateCounter(int length) {
+        boolean wasCounterOverflowed = mCounterOverflowed;
+        if (mCounterMaxLength == INVALID_MAX_LENGTH) {
+            mCounterView.setText(String.valueOf(length));
+            mCounterOverflowed = false;
+        } else {
+            mCounterOverflowed = length > mCounterMaxLength;
+            if (wasCounterOverflowed != mCounterOverflowed) {
+                mCounterView.setTextAppearance(getContext(), mCounterOverflowed ?
+                        mCounterOverflowTextAppearance : mCounterTextAppearance);
+            }
+            mCounterView.setText(getContext().getString(R.string.character_counter_pattern,
+                    length, mCounterMaxLength));
+        }
+        if (mEditText != null && wasCounterOverflowed != mCounterOverflowed) {
+            updateLabelState(false);
+            updateEditTextBackground();
+        }
+    }
+
+    private void updateEditTextBackground() {
+        ensureBackgroundDrawableStateWorkaround();
+
+        final Drawable editTextBackground = mEditText.getBackground();
+        if (editTextBackground == null) {
+            return;
+        }
+
+        if (mErrorShown && mErrorView != null) {
+            // Set a color filter of the error color
+            editTextBackground.setColorFilter(
+                    AppCompatDrawableManager.getPorterDuffColorFilter(
+                            mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
+        } else if (mCounterOverflowed && mCounterView != null) {
+            // Set a color filter of the counter color
+            editTextBackground.setColorFilter(
+                    AppCompatDrawableManager.getPorterDuffColorFilter(
+                            mCounterView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
+        } else {
+            // Else reset the color filter and refresh the drawable state so that the
+            // normal tint is used
+            editTextBackground.clearColorFilter();
+            mEditText.refreshDrawableState();
+        }
+    }
+
+    private void ensureBackgroundDrawableStateWorkaround() {
+        final Drawable bg = mEditText.getBackground();
+        if (bg == null) {
+            return;
+        }
+
+        if (!mHasReconstructedEditTextBackground) {
+            // This is gross. There is an issue in the platform which affects container Drawables
+            // where the first drawable retrieved from resources will propogate any changes
+            // (like color filter) to all instances from the cache. We'll try to workaround it...
+
+            final Drawable newBg = bg.getConstantState().newDrawable();
+
+            if (bg instanceof DrawableContainer) {
+                // If we have a Drawable container, we can try and set it's constant state via
+                // reflection from the new Drawable
+                mHasReconstructedEditTextBackground =
+                        DrawableUtils.setContainerConstantState(
+                                (DrawableContainer) bg, newBg.getConstantState());
+            }
+
+            if (!mHasReconstructedEditTextBackground) {
+                // If we reach here then we just need to set a brand new instance of the Drawable
+                // 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);
+                mHasReconstructedEditTextBackground = true;
+            }
+        }
     }
 
     /**
@@ -427,14 +743,17 @@
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
-        mCollapsingTextHelper.draw(canvas);
+
+        if (mHintEnabled) {
+            mCollapsingTextHelper.draw(canvas);
+        }
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        if (mEditText != null) {
+        if (mHintEnabled && mEditText != null) {
             final int l = mEditText.getLeft() + mEditText.getCompoundPaddingLeft();
             final int r = mEditText.getRight() - mEditText.getCompoundPaddingRight();
 
@@ -455,7 +774,7 @@
     public void refreshDrawableState() {
         super.refreshDrawableState();
         // Drawable state has changed so see if we need to update the label
-        updateLabelVisibility(ViewCompat.isLaidOut(this));
+        updateLabelState(ViewCompat.isLaidOut(this));
     }
 
     private void collapseHint(boolean animate) {
diff --git a/design/src/android/support/design/widget/ThemeUtils.java b/design/src/android/support/design/widget/ThemeUtils.java
new file mode 100644
index 0000000..327a44d
--- /dev/null
+++ b/design/src/android/support/design/widget/ThemeUtils.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.design.R;
+
+class ThemeUtils {
+
+    private static final int[] APPCOMPAT_CHECK_ATTRS = { R.attr.colorPrimary };
+
+    static void checkAppCompatTheme(Context context) {
+        TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);
+        final boolean failed = !a.hasValue(0);
+        if (a != null) {
+            a.recycle();
+        }
+        if (failed) {
+            throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "
+                    + "(or descendant) with the design library.");
+        }
+    }
+}
diff --git a/design/src/android/support/design/widget/ViewOffsetHelper.java b/design/src/android/support/design/widget/ViewOffsetHelper.java
index 6bde40b..1254f17 100644
--- a/design/src/android/support/design/widget/ViewOffsetHelper.java
+++ b/design/src/android/support/design/widget/ViewOffsetHelper.java
@@ -66,9 +66,9 @@
     }
 
     private static void tickleInvalidationFlag(View view) {
-        final float x = ViewCompat.getTranslationX(view);
-        ViewCompat.setTranslationX(view, x + 1);
-        ViewCompat.setTranslationX(view, x);
+        final float y = ViewCompat.getTranslationY(view);
+        ViewCompat.setTranslationY(view, y + 1);
+        ViewCompat.setTranslationY(view, y);
     }
 
     /**
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
index 63e93b7..06d8d6f 100644
--- a/graphics/drawable/Android.mk
+++ b/graphics/drawable/Android.mk
@@ -17,8 +17,8 @@
 #static vector drawable library
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-vectordrawable
-LOCAL_SDK_VERSION := 7
-LOCAL_SRC_FILES := $(call all-java-files-under, static)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, static util)
 
 LOCAL_JAVA_LIBRARIES := android-support-v4
 
@@ -29,8 +29,8 @@
 #Animated vector drawable library
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v11-animatedvectordrawable
-LOCAL_SDK_VERSION := 11
-LOCAL_SRC_FILES := $(call all-java-files-under, animated)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, animated util)
 
 LOCAL_JAVA_LIBRARIES := android-support-v4
 
@@ -38,4 +38,5 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable
 
+LOCAL_AAPT_FLAGS := --no-version-vectors
 include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
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 78ef62d..eff9670 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -16,7 +16,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
-import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -45,12 +44,12 @@
 /**
  * This class uses {@link android.animation.ObjectAnimator} and
  * {@link android.animation.AnimatorSet} to animate the properties of a
- * {@link android.graphics.drawable.VectorDrawableCompat} to create an animated drawable.
+ * {@link android.support.graphics.drawable.VectorDrawableCompat} to create an animated drawable.
  * <p>
  * AnimatedVectorDrawableCompat are normally defined as 3 separate XML files.
  * </p>
  * <p>
- * First is the XML file for {@link android.graphics.drawable.VectorDrawableCompat}. Note that we
+ * First is the XML file for {@link android.support.graphics.drawable.VectorDrawableCompat}. Note that we
  * allow the animation to happen on the group's attributes and path's attributes, which requires they
  * are uniquely named in this XML file. Groups and paths without animations do not need names.
  * </p>
@@ -306,9 +305,9 @@
                 }
                 if (ANIMATED_VECTOR.equals(tagName)) {
                     final TypedArray a =
-                            obtainAttributes(res, theme, attrs, R.styleable.AnimatedVectorDrawable);
+                            obtainAttributes(res, theme, attrs, AndroidResources.styleable_AnimatedVectorDrawable);
 
-                    int drawableRes = a.getResourceId(R.styleable.AnimatedVectorDrawable_drawable,
+                    int drawableRes = a.getResourceId(AndroidResources.styleable_AnimatedVectorDrawable_drawable,
                             0);
                     if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                         Log.v(LOGTAG, "drawableRes is " + drawableRes);
@@ -327,11 +326,11 @@
                     a.recycle();
                 } else if (TARGET.equals(tagName)) {
                     final TypedArray a =
-                            res.obtainAttributes(attrs, R.styleable.AnimatedVectorDrawableTarget);
+                            res.obtainAttributes(attrs, AndroidResources.styleable_AnimatedVectorDrawableTarget);
                     final String target = a.getString(
-                            R.styleable.AnimatedVectorDrawableTarget_name);
+                            AndroidResources.styleable_AnimatedVectorDrawableTarget_name);
 
-                    int id = a.getResourceId(R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+                    int id = a.getResourceId(AndroidResources.styleable_AnimatedVectorDrawableTarget_animation, 0);
                     if (id != 0) {
                         Animator objectAnimator = AnimatorInflater.loadAnimator(mContext, id);
                         setupAnimatorsForTarget(target, objectAnimator);
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
index a92c3e5..8503fae 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
@@ -131,8 +131,8 @@
         }
 
         for (int i = 0; i < nodesFrom.length; i ++) {
-            if (nodesFrom[i].mType != nodesTo[i].mType
-                    || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+            if (nodesFrom[i].type != nodesTo[i].type
+                    || nodesFrom[i].params.length != nodesTo[i].params.length) {
                 return false;
             }
         }
@@ -148,9 +148,9 @@
      */
     public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
         for (int i = 0; i < source.length; i ++) {
-            target[i].mType = source[i].mType;
-            for (int j = 0; j < source[i].mParams.length; j ++) {
-                target[i].mParams[j] = source[i].mParams[j];
+            target[i].type = source[i].type;
+            for (int j = 0; j < source[i].params.length; j ++) {
+                target[i].params[j] = source[i].params[j];
             }
         }
     }
@@ -288,17 +288,18 @@
      * An array of PathDataNode can represent the whole "d" attribute.
      */
     public static class PathDataNode {
-        private char mType;
-        private float[] mParams;
+        /*package*/
+        char type;
+        float[] params;
 
         private PathDataNode(char type, float[] params) {
-            mType = type;
-            mParams = params;
+            this.type = type;
+            this.params = params;
         }
 
         private PathDataNode(PathDataNode n) {
-            mType = n.mType;
-            mParams = copyOfRange(n.mParams, 0, n.mParams.length);
+            type = n.type;
+            params = copyOfRange(n.params, 0, n.params.length);
         }
 
         /**
@@ -311,8 +312,8 @@
             float[] current = new float[6];
             char previousCommand = 'm';
             for (int i = 0; i < node.length; i++) {
-                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
-                previousCommand = node[i].mType;
+                addCommand(path, current, previousCommand, node[i].type, node[i].params);
+                previousCommand = node[i].type;
             }
         }
 
@@ -327,9 +328,9 @@
          */
         public void interpolatePathDataNode(PathDataNode nodeFrom,
                 PathDataNode nodeTo, float fraction) {
-            for (int i = 0; i < nodeFrom.mParams.length; i++) {
-                mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
-                        + nodeTo.mParams[i] * fraction;
+            for (int i = 0; i < nodeFrom.params.length; i++) {
+                params[i] = nodeFrom.params[i] * (1 - fraction)
+                        + nodeTo.params[i] * fraction;
             }
         }
 
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 d33c204..c0e5b40 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -196,7 +196,7 @@
     private static final int LINEJOIN_ROUND = 1;
     private static final int LINEJOIN_BEVEL = 2;
 
-    private static final boolean DBG_VECTOR_DRAWABLE = true;
+    private static final boolean DBG_VECTOR_DRAWABLE = false;
 
     private VectorDrawableState mVectorState;
 
@@ -420,7 +420,6 @@
 
             final VectorDrawableCompat drawable = new VectorDrawableCompat();
             drawable.inflate(res, parser, attrs, theme);
-
             return drawable;
         } catch (XmlPullParserException e) {
             Log.e(LOGTAG, "parser error", e);
@@ -462,8 +461,9 @@
         final VPathRenderer pathRenderer = new VPathRenderer();
         state.mVPathRenderer = pathRenderer;
 
-        final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
-        updateStateFromTypedArray(a);
+        final TypedArray a = obtainAttributes(res, theme, attrs, AndroidResources.styleable_VectorDrawableTypeArray);
+
+        updateStateFromTypedArray(a, parser);
         a.recycle();
         state.mChangingConfigurations = getChangingConfigurations();
         state.mCacheDirty = true;
@@ -472,30 +472,47 @@
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
-    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+
+    /**
+     * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
+     * attribute's enum value.
+     */
+    private static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+        switch (value) {
+            case 3: return Mode.SRC_OVER;
+            case 5: return Mode.SRC_IN;
+            case 9: return Mode.SRC_ATOP;
+            case 14: return Mode.MULTIPLY;
+            case 15: return Mode.SCREEN;
+            case 16: return Mode.ADD;
+            default: return defaultMode;
+        }
+    }
+
+    private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) throws XmlPullParserException {
         final VectorDrawableState state = mVectorState;
         final VPathRenderer pathRenderer = state.mVPathRenderer;
 
         // Account for any configuration changes.
         // state.mChangingConfigurations |= Utils.getChangingConfigurations(a);
 
-        final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
-        // if (tintMode != -1) {
-        // state.mTintMode = Utils.parseTintMode(tintMode, DEFAULT_TINT_MODE);
-        // }
+        final int mode = TypedArrayUtils.getNamedInt(a, parser, "tintMode",
+                AndroidResources.styleable_VectorDrawable_Mode, -1);
+        state.mTintMode = parseTintMode(mode, Mode.SRC_IN);
 
-        final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
+        final ColorStateList tint = a.getColorStateList(AndroidResources.styleable_VectorDrawable_tint);
         if (tint != null) {
             state.mTint = tint;
         }
 
-        state.mAutoMirrored = a.getBoolean(
-                R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
+        state.mAutoMirrored = TypedArrayUtils.getNamedBoolean(a, parser, "autoMirrored",
+                    AndroidResources.styleable_VectorDrawable_autoMirrored, state.mAutoMirrored);
 
-        pathRenderer.mViewportWidth = a.getFloat(
-                R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
-        pathRenderer.mViewportHeight = a.getFloat(
-                R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+        pathRenderer.mViewportWidth = TypedArrayUtils.getNamedFloat(a, parser, "viewportWidth",
+                AndroidResources.styleable_VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
+
+        pathRenderer.mViewportHeight = TypedArrayUtils.getNamedFloat(a, parser, "viewportHeight",
+                AndroidResources.styleable_VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
 
         if (pathRenderer.mViewportWidth <= 0) {
             throw new XmlPullParserException(a.getPositionDescription() +
@@ -506,10 +523,9 @@
         }
 
         pathRenderer.mBaseWidth = a.getDimension(
-                R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
+                AndroidResources.styleable_VectorDrawable_width, pathRenderer.mBaseWidth);
         pathRenderer.mBaseHeight = a.getDimension(
-                R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
-
+                AndroidResources.styleable_VectorDrawable_height, pathRenderer.mBaseHeight);
         if (pathRenderer.mBaseWidth <= 0) {
             throw new XmlPullParserException(a.getPositionDescription() +
                     "<vector> tag requires width > 0");
@@ -518,11 +534,12 @@
                     "<vector> tag requires height > 0");
         }
 
-        final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
-                pathRenderer.getAlpha());
+        // shown up from API 11.
+        final float alphaInFloat = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
+                    AndroidResources.styleable_VectorDrawable_alpha, pathRenderer.getAlpha());
         pathRenderer.setAlpha(alphaInFloat);
 
-        final String name = a.getString(R.styleable.VectorDrawable_name);
+        final String name = a.getString(AndroidResources.styleable_VectorDrawable_name);
         if (name != null) {
             pathRenderer.mRootName = name;
             pathRenderer.mVGTargetsMap.put(name, pathRenderer);
@@ -545,10 +562,9 @@
             if (eventType == XmlPullParser.START_TAG) {
                 final String tagName = parser.getName();
                 final VGroup currentGroup = groupStack.peek();
-                Log.v(LOGTAG, tagName);
                 if (SHAPE_PATH.equals(tagName)) {
                     final VFullPath path = new VFullPath();
-                    path.inflate(res, attrs, theme);
+                    path.inflate(res, attrs, theme, parser);
                     currentGroup.mChildren.add(path);
                     if (path.getPathName() != null) {
                         pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
@@ -557,7 +573,7 @@
                     state.mChangingConfigurations |= path.mChangingConfigurations;
                 } else if (SHAPE_CLIP_PATH.equals(tagName)) {
                     final VClipPath path = new VClipPath();
-                    path.inflate(res, attrs, theme);
+                    path.inflate(res, attrs, theme, parser);
                     currentGroup.mChildren.add(path);
                     if (path.getPathName() != null) {
                         pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
@@ -565,7 +581,7 @@
                     state.mChangingConfigurations |= path.mChangingConfigurations;
                 } else if (SHAPE_GROUP.equals(tagName)) {
                     VGroup newChildGroup = new VGroup();
-                    newChildGroup.inflate(res, attrs, theme);
+                    newChildGroup.inflate(res, attrs, theme, parser);
                     currentGroup.mChildren.add(newChildGroup);
                     groupStack.push(newChildGroup);
                     if (newChildGroup.getGroupName() != null) {
@@ -614,6 +630,8 @@
             Object child = currentGroup.mChildren.get(i);
             if (child instanceof VGroup) {
                 printGroupTree((VGroup) child, level + 1);
+            } else {
+                ((VPath) child).printVPath(level + 1);
             }
         }
     }
@@ -1017,29 +1035,41 @@
             return mLocalMatrix;
         }
 
-        public void inflate(Resources res, AttributeSet attrs, Theme theme) {
+        public void inflate(Resources res, AttributeSet attrs, Theme theme, XmlPullParser parser) {
             final TypedArray a = obtainAttributes(res, theme, attrs,
-                    R.styleable.VectorDrawableGroup);
-            updateStateFromTypedArray(a);
+                    AndroidResources.styleable_VectorDrawableGroup);
+            updateStateFromTypedArray(a, parser);
             a.recycle();
         }
 
-        private void updateStateFromTypedArray(TypedArray a) {
+        private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) {
             // Account for any configuration changes.
             // mChangingConfigurations |= Utils.getChangingConfigurations(a);
 
             // Extract the theme attributes, if any.
             mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
 
-            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
-            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
-            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
-            mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
-            mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
-            mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
-            mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+            // This is added in API 11
+            mRotate = TypedArrayUtils.getNamedFloat(a, parser, "rotation",
+                    AndroidResources.styleable_VectorDrawableGroup_rotation, mRotate);
 
-            final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
+            mPivotX = a.getFloat(AndroidResources.styleable_VectorDrawableGroup_pivotX, mPivotX);
+            mPivotY = a.getFloat(AndroidResources.styleable_VectorDrawableGroup_pivotY, mPivotY);
+
+            // This is added in API 11
+            mScaleX = TypedArrayUtils.getNamedFloat(a, parser, "scaleX",
+                    AndroidResources.styleable_VectorDrawableGroup_scaleX, mScaleX);
+
+            // This is added in API 11
+            mScaleY = TypedArrayUtils.getNamedFloat(a, parser, "scaleY",
+                    AndroidResources.styleable_VectorDrawableGroup_scaleY, mScaleY);
+
+            mTranslateX = TypedArrayUtils.getNamedFloat(a, parser, "translateX",
+                    AndroidResources.styleable_VectorDrawableGroup_translateX, mTranslateX);
+            mTranslateY = TypedArrayUtils.getNamedFloat(a, parser, "translateY",
+                    AndroidResources.styleable_VectorDrawableGroup_translateY, mTranslateY);
+
+            final String groupName = a.getString(AndroidResources.styleable_VectorDrawableGroup_name);
             if (groupName != null) {
                 mGroupName = groupName;
             }
@@ -1162,6 +1192,28 @@
             // Empty constructor.
         }
 
+        public void printVPath(int level) {
+            String indent = "";
+            for (int i = 0; i < level; i++) {
+                indent += "    ";
+            }
+            Log.v(LOGTAG, indent + "current path is :" + mPathName +
+                    " pathData is " + NodesToString(mNodes));
+
+        }
+
+        public String NodesToString(PathParser.PathDataNode[] nodes) {
+            String result = " ";
+            for (int i = 0; i < nodes.length; i++) {
+                result += nodes[i].type + ":";
+                float[] params = nodes[i].params;
+                for (int j = 0; j < params.length; j++) {
+                    result += params[j] + ",";
+                }
+            }
+            return result;
+        }
+
         public VPath(VPath copy) {
             mPathName = copy.mPathName;
             mChangingConfigurations = copy.mChangingConfigurations;
@@ -1219,10 +1271,14 @@
             super(copy);
         }
 
-        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+        public void inflate(Resources r, AttributeSet attrs, Theme theme, XmlPullParser parser) {
             // TODO TINT THEME Not supported yet
+            final boolean hasPathData = TypedArrayUtils.hasAttribute(parser, "pathData");
+            if (!hasPathData) {
+                return;
+            }
             final TypedArray a = obtainAttributes(r, theme, attrs,
-                    R.styleable.VectorDrawableClipPath);
+                    AndroidResources.styleable_VectorDrawableClipPath);
             updateStateFromTypedArray(a);
             a.recycle();
         }
@@ -1231,12 +1287,12 @@
             // Account for any configuration changes.
             // mChangingConfigurations |= Utils.getChangingConfigurations(a);;
 
-            final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+            final String pathName = a.getString(AndroidResources.styleable_VectorDrawableClipPath_name);
             if (pathName != null) {
                 mPathName = pathName;
             }
 
-            final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
+            final String pathData = a.getString(AndroidResources.styleable_VectorDrawableClipPath_pathData);
             if (pathData != null) {
                 mNodes = PathParser.createNodesFromPathData(pathData);
             }
@@ -1325,52 +1381,64 @@
             return mThemeAttrs != null;
         }
 
-        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+        public void inflate(Resources r, AttributeSet attrs, Theme theme, XmlPullParser parser) {
             final TypedArray a = obtainAttributes(r, theme, attrs,
-                    R.styleable.VectorDrawablePath);
-            updateStateFromTypedArray(a);
+                    AndroidResources.styleable_VectorDrawablePath);
+            updateStateFromTypedArray(a, parser);
             a.recycle();
         }
 
-        private void updateStateFromTypedArray(TypedArray a) {
+        private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) {
             // Account for any configuration changes.
             // mChangingConfigurations |= Utils.getChangingConfigurations(a);
 
             // Extract the theme attributes, if any.
             mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
 
-            final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
+            // In order to work around the conflicting id issue, we need to double check the existence
+            // of the attribute.
+            // B/c if the attribute existed in the compiled XML, then calling TypedArray will be safe
+            // since the framework will look up in the XML first.
+            // Note that each getAttributeValue take roughly 0.03ms, it is a price we have to pay here.
+            final boolean hasPathData = TypedArrayUtils.hasAttribute(parser, "pathData");
+            if (!hasPathData) {
+                //If there is no pathData in the <path> tag, then this is an empty path, nothing need to be drawn.
+                return;
+            }
+
+            final String pathName = a.getString(AndroidResources.styleable_VectorDrawablePath_name);
             if (pathName != null) {
                 mPathName = pathName;
             }
-
-            final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
+            final String pathData = a.getString(AndroidResources.styleable_VectorDrawablePath_pathData);
             if (pathData != null) {
                 mNodes = PathParser.createNodesFromPathData(pathData);
             }
 
-            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
-                    mFillColor);
-            mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha,
-                    mFillAlpha);
-            mStrokeLineCap = getStrokeLineCap(a.getInt(
-                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
-            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
-                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
-            mStrokeMiterlimit = a.getFloat(
-                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
-            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor,
-                    mStrokeColor);
-            mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
-                    mStrokeAlpha);
-            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
-                    mStrokeWidth);
-            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
-                    mTrimPathEnd);
-            mTrimPathOffset = a.getFloat(
-                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
-            mTrimPathStart = a.getFloat(
-                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+            mFillColor = TypedArrayUtils.getNamedColor(a, parser, "fillColor",
+                    AndroidResources.styleable_VectorDrawablePath_fillColor, mFillColor);
+            mFillAlpha = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
+                    AndroidResources.styleable_VectorDrawablePath_fillAlpha, mFillAlpha);
+            final int lineCap = TypedArrayUtils.getNamedInt(a, parser, "strokeLineCap",
+                    AndroidResources.styleable_VectorDrawablePath_strokeLineCap, -1);
+            mStrokeLineCap = getStrokeLineCap(lineCap, mStrokeLineCap);
+            final int lineJoin = TypedArrayUtils.getNamedInt(a, parser, "strokeLineJoin",
+                    AndroidResources.styleable_VectorDrawablePath_strokeLineJoin, -1);
+            mStrokeLineJoin = getStrokeLineJoin(lineJoin, mStrokeLineJoin);
+            mStrokeMiterlimit = TypedArrayUtils.getNamedFloat(a, parser, "strokeMiterLimit",
+                    AndroidResources.styleable_VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
+            mStrokeColor = TypedArrayUtils.getNamedColor(a, parser, "strokeColor",
+                    AndroidResources.styleable_VectorDrawablePath_strokeColor, mStrokeColor);
+            mStrokeAlpha = TypedArrayUtils.getNamedFloat(a, parser, "strokeAlpha",
+                    AndroidResources.styleable_VectorDrawablePath_strokeAlpha, mStrokeAlpha);
+            mStrokeWidth = TypedArrayUtils.getNamedFloat(a, parser, "strokeWidth",
+                    AndroidResources.styleable_VectorDrawablePath_strokeWidth, mStrokeWidth);
+            mTrimPathEnd = TypedArrayUtils.getNamedFloat(a, parser, "trimPathEnd",
+                    AndroidResources.styleable_VectorDrawablePath_trimPathEnd, mTrimPathEnd);
+            mTrimPathOffset = TypedArrayUtils.getNamedFloat(a, parser, "trimPathOffset",
+                    AndroidResources.styleable_VectorDrawablePath_trimPathOffset, mTrimPathOffset);
+            mTrimPathStart = TypedArrayUtils.getNamedFloat(a, parser, "trimPathStart",
+                    AndroidResources.styleable_VectorDrawablePath_trimPathStart, mTrimPathStart);
         }
 
         @Override
@@ -1381,7 +1449,7 @@
 
             /*
              * TODO TINT THEME Not supported yet final TypedArray a =
-             * t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+             * t.resolveAttributes(mThemeAttrs, styleable_VectorDrawablePath);
              * updateStateFromTypedArray(a); a.recycle();
              */
         }
diff --git a/graphics/drawable/testanimated/Android.mk b/graphics/drawable/testanimated/Android.mk
index c888d9e..004cddb 100644
--- a/graphics/drawable/testanimated/Android.mk
+++ b/graphics/drawable/testanimated/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SDK_VERSION := 11
+LOCAL_SDK_VERSION := current
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -30,6 +30,8 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v11-animatedvectordrawable android-support-v4
 
-LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages android.support.graphics.drawable
+LOCAL_AAPT_FLAGS += --auto-add-overlay \
+        --extra-packages android.support.graphics.drawable \
+        --no-version-vectors
 
 include $(BUILD_PACKAGE)
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
index 7c3b1de..dac981b 100644
--- a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
@@ -14,14 +14,13 @@
      limitations under the License.
 -->
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:drawable="@drawable/vector_drawable_grouping_1" >
+    android:drawable="@drawable/vector_drawable_grouping_1" >
 
     <target
-        auto:name="sun"
-        auto:animation="@anim/animation_grouping_1_01" />
+        android:name="sun"
+        android:animation="@anim/animation_grouping_1_01" />
     <target
-        auto:name="earth"
-        auto:animation="@anim/animation_grouping_1_01" />
+        android:name="earth"
+        android:animation="@anim/animation_grouping_1_01" />
 
 </animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
index e37d2a1..2944dc2 100644
--- a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
@@ -14,13 +14,12 @@
      limitations under the License.
 -->
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:drawable="@drawable/vector_drawable_progress_bar" >
+    android:drawable="@drawable/vector_drawable_progress_bar" >
 
     <target
-        auto:name="pie1"
-        auto:animation="@anim/trim_path_animation_progress_bar" />
+        android:name="pie1"
+        android:animation="@anim/trim_path_animation_progress_bar" />
     <target
-        auto:name="root_bar"
-        auto:animation="@anim/alpha_animation_progress_bar" />
+        android:name="root_bar"
+        android:animation="@anim/alpha_animation_progress_bar" />
 </animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
index eceda71..06f098e 100644
--- a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
@@ -14,37 +14,36 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="256"
-        auto:viewportWidth="256" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="256"
+        android:viewportWidth="256" >
 
     <group
-        auto:name="shape_layer_1"
-        auto:translateX="128"
-        auto:translateY="128" >
-        <group auto:name="sun" >
+        android:name="shape_layer_1"
+        android:translateX="128"
+        android:translateY="128" >
+        <group android:name="sun" >
             <path
-                auto:name="ellipse_path_1"
-                auto:fillColor="#ffff8000"
-                auto:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
+                android:name="ellipse_path_1"
+                android:fillColor="#ffff8000"
+                android:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
 
             <group
-                auto:name="earth"
-                auto:translateX="75" >
+                android:name="earth"
+                android:translateX="75" >
                 <path
-                    auto:name="ellipse_path_1_1"
-                    auto:fillColor="#ff5656ea"
-                    auto:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
+                    android:name="ellipse_path_1_1"
+                    android:fillColor="#ff5656ea"
+                    android:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
 
                 <group
-                    auto:name="moon"
-                    auto:translateX="25" >
+                    android:name="moon"
+                    android:translateX="25" >
                     <path
-                        auto:name="ellipse_path_1_2"
-                        auto:fillColor="#ffadadad"
-                        auto:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
+                        android:name="ellipse_path_1_2"
+                        android:fillColor="#ffadadad"
+                        android:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
                 </group>
             </group>
         </group>
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
index 0b8884b..535265e 100644
--- a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
@@ -14,36 +14,35 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="64"
-        auto:viewportWidth="64"
-        auto:name="root_bar" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="64"
+        android:viewportWidth="64"
+        android:name="root_bar" >
 
     <group
-        auto:name="root"
-        auto:pivotX="0.0"
-        auto:pivotY="0.0"
-        auto:rotation="0"
-        auto:translateX="32.0"
-        auto:translateY="32.0" >
+        android:name="root"
+        android:pivotX="0.0"
+        android:pivotY="0.0"
+        android:rotation="0"
+        android:translateX="32.0"
+        android:translateY="32.0" >
         <group
-            auto:name="rotationGroup"
-            auto:pivotX="0.0"
-            auto:pivotY="0.0"
-            auto:rotation="0" >
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="0" >
             <path
-                auto:name="pie1"
-                auto:fillColor="#00000000"
-                auto:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
-                auto:strokeColor="#FF00FFFF"
-                auto:strokeLineCap="round"
-                auto:strokeLineJoin="miter"
-                auto:strokeWidth="2"
-                auto:trimPathEnd="0.1"
-                auto:trimPathOffset="0"
-                auto:trimPathStart="0" />
+                android:name="pie1"
+                android:fillColor="#00000000"
+                android:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
+                android:strokeColor="#FF00FFFF"
+                android:strokeLineCap="round"
+                android:strokeLineJoin="miter"
+                android:strokeWidth="2"
+                android:trimPathEnd="0.1"
+                android:trimPathOffset="0"
+                android:trimPathStart="0" />
         </group>
     </group>
 
diff --git a/graphics/drawable/teststatic/Android.mk b/graphics/drawable/teststatic/Android.mk
index d8a0fd7..4c4a7ba 100644
--- a/graphics/drawable/teststatic/Android.mk
+++ b/graphics/drawable/teststatic/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SDK_VERSION := 7
+LOCAL_SDK_VERSION := current
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -32,7 +32,8 @@
 
 LOCAL_AAPT_FLAGS := \
         --auto-add-overlay \
-        --extra-packages android.support.graphics.drawable
+        --extra-packages android.support.graphics.drawable \
+        --no-version-vectors
 
 include $(BUILD_PACKAGE)
 
diff --git a/graphics/drawable/teststatic/AndroidManifest.xml b/graphics/drawable/teststatic/AndroidManifest.xml
index 19586fb..39ac8ba 100644
--- a/graphics/drawable/teststatic/AndroidManifest.xml
+++ b/graphics/drawable/teststatic/AndroidManifest.xml
@@ -17,7 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.support.test.vectordrawable" >
 
-    <uses-sdk android:minSdkVersion="7" />
+    <uses-sdk android:minSdkVersion="7"/>
 
     <application android:icon="@drawable/app_sample_code" android:label="VectorDrawableCompatTest" >
         <activity android:name="android.support.test.vectordrawable.TestActivity" />
@@ -29,4 +29,4 @@
         </intent-filter>
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
index 12357ef..286b487 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
  Copyright (C) 2015 The Android Open Source Project
 
@@ -15,20 +14,16 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:height="48dp"
-    auto:viewportHeight="480"
-    auto:viewportWidth="480"
-    auto:width="48dp" >
+        android:height="48dp"
+        android:width="48dp"
+        android:viewportHeight="480"
+        android:viewportWidth="480" >
 
     <group>
         <path
-            auto:name="box1"
-            auto:fillColor="?android:attr/textColorPrimary"
-            auto:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
-            auto:strokeColor="?android:attr/colorBackground"
-            auto:strokeLineCap="round"
-            auto:strokeLineJoin="round" />
+            android:name="box1"
+            android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
+            android:strokeLineCap="round"
+            android:strokeLineJoin="round" />
     </group>
-
-</vector>
\ No newline at end of file
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
index cb6b9df..7567887 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
@@ -1,5 +1,4 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,24 +13,20 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:height="64dp"
-    auto:viewportHeight="320"
-    auto:viewportWidth="320"
-    auto:width="64dp" >
-
+        android:width="64dp"
+        android:height="64dp" android:viewportWidth="320"
+          android:viewportHeight="320">
     <group
-        auto:pivotX="70"
-        auto:pivotY="120"
-        auto:rotation="180" >
+        android:rotation="180"
+        android:pivotX="70"
+        android:pivotY="120">
         <path
-            auto:name="house"
-            auto:fillColor="#ff440000"
-            auto:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeWidth="10"
-            auto:trimPathEnd=".9"
-            auto:trimPathStart=".1" />
+            android:name="house"
+            android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
+            android:fillColor="#ff440000"
+            android:strokeColor="#FF00FF00"
+            android:strokeWidth="10"
+            android:trimPathStart=".1"
+            android:trimPathEnd=".9"/>
     </group>
-
-</vector>
\ No newline at end of file
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
index 37d0086..454468a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
@@ -14,51 +14,57 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:height="64dp"
-    auto:viewportHeight="12.25"
-    auto:viewportWidth="7.30625"
-    auto:width="64dp" >
+    android:height="64dp"
+    android:viewportHeight="12.25"
+    android:viewportWidth="7.30625"
+    android:width="64dp" >
 
     <group
-        auto:pivotX="3.65"
-        auto:pivotY="6.125"
-        auto:rotation="-30" >
+        android:pivotX="3.65"
+        android:pivotY="6.125"
+        android:rotation="-30" >
         <clip-path
-            auto:name="clip1"
-            auto:pathData="
+            android:name="clip1"
+            android:pathData="
                 M 0, 6.125
                 l 7.3, 0
                 l 0, 12.25
                 l-7.3, 0
                 z" />
-    </group>
-    <group>
-        <path
-            auto:name="one"
-            auto:fillColor="#ff88ff"
-            auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+
+        <group
+            android:pivotX="3.65"
+            android:pivotY="6.125"
+            android:rotation="30" >
+            <path
+                android:name="one"
+                android:fillColor="#ff88ff"
+                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
                 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
                 l-5.046875,0.0 0.0-1.0Z" />
+        </group>
     </group>
     <group
-        auto:pivotX="3.65"
-        auto:pivotY="6.125"
-        auto:rotation="-30" >
+        android:pivotX="3.65"
+        android:pivotY="6.125"
+        android:rotation="-30" >
         <clip-path
-            auto:name="clip2"
-            auto:pathData="
+            android:name="clip2"
+            android:pathData="
                 M 0, 0
                 l 7.3, 0
                 l 0, 6.125
                 l-7.3, 0
                 z" />
-    </group>
-    <group>
-        <path
-            auto:name="two"
-            auto:fillColor="#ff88ff"
-            auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+
+        <group
+            android:pivotX="3.65"
+            android:pivotY="6.125"
+            android:rotation="30" >
+            <path
+                android:name="two"
+                android:fillColor="#ff88ff"
+                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
                         q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
                         q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
                         q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
@@ -67,6 +73,7 @@
                         q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
                         q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
                         q-0.78125024,0.8125-2.2187502,2.265625Z" />
+        </group>
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
index 4e2086f..e6658a6 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
@@ -13,38 +13,41 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-            auto:width="64dp"
-            auto:height="64dp"
-            auto:viewportWidth="7.30625"
-            auto:viewportHeight="12.25"
-            auto:autoMirrored="true">
+    android:autoMirrored="true"
+    android:height="64dp"
+    android:viewportHeight="12.25"
+    android:viewportWidth="7.30625"
+    android:width="64dp" >
 
     <group>
         <clip-path
-                auto:name="clip1"
-                auto:pathData="
+            android:name="clip1"
+            android:pathData="
                 M 3.65, 6.125
                 m-.001, 0
                 a .001,.001 0 1,0 .002,0
-                a .001,.001 0 1,0-.002,0z"/>
-        <path
-                auto:name="one"
-                auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
-                l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l-5.046875,0.0 0.0-1.0Z"
-                auto:fillColor="#ff88ff"/>
+                a .001,.001 0 1,0-.002,0z" />
 
+        <path
+            android:name="one"
+            android:fillColor="#ff88ff"
+            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+                l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+                l-5.046875,0.0 0.0-1.0Z" />
+    </group>
+    <group>
         <clip-path
-                auto:name="clip2"
-                auto:pathData="
+            android:name="clip2"
+            android:pathData="
                 M 3.65, 6.125
                 m-6, 0
                 a 6,6 0 1,0 12,0
-                a 6,6 0 1,0-12,0z"/>
+                a 6,6 0 1,0-12,0z" />
+
         <path
-                auto:name="two"
-                auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+            android:name="two"
+            android:fillColor="#ff88ff"
+            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
                         q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
                         q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
                         q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
@@ -52,7 +55,7 @@
                         q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
                         q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
                         q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
-                        q-0.78125024,0.8125-2.2187502,2.265625Z"
-                auto:fillColor="#ff88ff"/>
+                        q-0.78125024,0.8125-2.2187502,2.265625Z" />
     </group>
-</vector>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
index 48801e3..d1723dc 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
@@ -14,24 +14,23 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="12.25"
-        auto:viewportWidth="7.30625" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="12.25"
+        android:viewportWidth="7.30625" >
 
     <group>
         <path
-            auto:name="one"
-            auto:fillColor="#ffff00"
-            auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+            android:name="one"
+            android:fillColor="#ffff00"
+            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
                 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
                 l-5.046875,0.0 0.0-1.0Z" />
         <path
-            auto:name="two"
-            auto:fillColor="#ffff00"
-            auto:fillAlpha="0"
-            auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+            android:name="two"
+            android:fillColor="#ffff00"
+            android:fillAlpha="0"
+            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
                         q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
                         q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
                         q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
index 24173e2..4b530fd 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
@@ -13,37 +13,36 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-            auto:width="64dp"
-            auto:height="64dp"
-            auto:viewportWidth="700"
-            auto:viewportHeight="700">
+            android:width="64dp"
+            android:height="64dp"
+            android:viewportWidth="700"
+            android:viewportHeight="700">
 
     <group>
-        <path auto:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
-              auto:name="path2451"
-              auto:fillColor="#00000000"
-              auto:strokeColor="#FF000000"
-              auto:strokeWidth="30.65500000000000"/>
-        <path auto:pathData="M 365.015 311.066"
-              auto:name="path2453"
-              auto:fillColor="#00000000"
-              auto:strokeColor="#FF000000"
-              auto:strokeWidth="30.655000000000001"/>
-        <path auto:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
-              auto:name="path2455"
-              auto:strokeColor="#FF000000"
-              auto:fillColor="#FFFFFFFF"
-              auto:strokeWidth="30.655000000000001"/>
-        <path auto:pathData="M 170.515 451.566L 305.61 313.46"
-              auto:name="path2457"
-              auto:fillColor="#00000000"
-              auto:strokeColor="#000000"
-              auto:strokeWidth="30.655000000000001"/>
-        <path auto:pathData="M 557.968 449.974L 426.515 315.375"
-              auto:name="path2459"
-              auto:fillColor="#00000000"
-              auto:strokeColor="#000000"
-              auto:strokeWidth="30.655000000000001"/>
+        <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
+              android:name="path2451"
+              android:fillColor="#00000000"
+              android:strokeColor="#FF000000"
+              android:strokeWidth="30.65500000000000"/>
+        <path android:pathData="M 365.015 311.066"
+              android:name="path2453"
+              android:fillColor="#00000000"
+              android:strokeColor="#FF000000"
+              android:strokeWidth="30.655000000000001"/>
+        <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
+              android:name="path2455"
+              android:strokeColor="#FF000000"
+              android:fillColor="#FFFFFFFF"
+              android:strokeWidth="30.655000000000001"/>
+        <path android:pathData="M 170.515 451.566L 305.61 313.46"
+              android:name="path2457"
+              android:fillColor="#00000000"
+              android:strokeColor="#000000"
+              android:strokeWidth="30.655000000000001"/>
+        <path android:pathData="M 557.968 449.974L 426.515 315.375"
+              android:name="path2459"
+              android:fillColor="#00000000"
+              android:strokeColor="#000000"
+              android:strokeWidth="30.655000000000001"/>
     </group>
 </vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
index 90435d3..bbf2451 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
@@ -13,18 +13,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-            auto:width="64dp"
-            auto:height="64dp" auto:viewportWidth="140"
-          auto:viewportHeight="110">
+            android:width="64dp"
+            android:height="64dp" android:viewportWidth="140"
+          android:viewportHeight="110">
 
     <group>
         <path
-                auto:name="back"
-                auto:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
+                android:name="back"
+                android:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
               M 27,50 l 97,0 0,10-97,0 z
               M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z"
-                auto:fillColor="#ffffffff"
+                android:fillColor="#ffffffff"
                 />
     </group>
 </vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
index 251d694..e5b59df 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
@@ -13,18 +13,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-            auto:width="64dp"
-            auto:height="64dp" auto:viewportWidth="600"
-          auto:viewportHeight="600">
+            android:width="64dp"
+            android:height="64dp" android:viewportWidth="600"
+          android:viewportHeight="600">
 
     <group>
         <path
-                auto:name="pie1"
-                auto:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
-                auto:fillColor="#ffffcc00"
-                auto:strokeColor="#FF00FF00"
-                auto:strokeWidth="1"/>
+                android:name="pie1"
+                android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
+                android:fillColor="#ffffcc00"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="1"/>
     </group>
 
 </vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
index eccb0d0..ce2441d 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
@@ -14,20 +14,19 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="200"
-        auto:viewportWidth="200" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="200"
+        android:viewportWidth="200" >
 
     <group
-        auto:pivotX="100"
-        auto:pivotY="100"
-        auto:rotation="90">
+        android:pivotX="100"
+        android:pivotY="100"
+        android:rotation="90">
         <path
-            auto:name="house"
-            auto:fillColor="#ffffffff"
-            auto:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
+            android:name="house"
+            android:fillColor="#ffffffff"
+            android:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
index b26d30d..935d4a5 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
@@ -15,29 +15,28 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportWidth="200"
-        auto:viewportHeight="200">
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportWidth="200"
+        android:viewportHeight="200">
 
     <group>
         <path
-            auto:name="bar3"
-            auto:fillColor="#FFFFFFFF"
-            auto:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
+            android:name="bar3"
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
         <path
-            auto:name="bar2"
-            auto:fillColor="#FFFFFFFF"
-            auto:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
+            android:name="bar2"
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
         <path
-            auto:name="bar1"
-            auto:fillColor="#FF555555"
-            auto:pathData="M14.001,34.645   L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
+            android:name="bar1"
+            android:fillColor="#FF555555"
+            android:pathData="M14.001,34.645   L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
         <path
-            auto:name="bar0"
-            auto:fillColor="#FF555555"
-            auto:pathData="M0,20.502l6.999,7.071   c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
+            android:name="bar0"
+            android:fillColor="#FF555555"
+            android:pathData="M0,20.502l6.999,7.071   c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
index eb440f5..05f481b 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
@@ -14,23 +14,22 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="80"
-        auto:viewportWidth="40" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="80"
+        android:viewportWidth="40" >
 
     <group>
         <path
-            auto:name="battery"
-            auto:fillColor="#3388ff"
-            auto:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
-            auto:strokeColor="#ff8833"
-            auto:strokeWidth="1" />
+            android:name="battery"
+            android:fillColor="#3388ff"
+            android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+            android:strokeColor="#ff8833"
+            android:strokeWidth="1" />
         <path
-            auto:name="spark"
-            auto:fillColor="#FFFF0000"
-            auto:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
+            android:name="spark"
+            android:fillColor="#FFFF0000"
+            android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
index 94a23e8..94338a7 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
@@ -14,79 +14,78 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:name="rootGroup"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="600"
-        auto:viewportWidth="600"
-        auto:alpha="0.5" >
+        android:name="rootGroup"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="600"
+        android:viewportWidth="600"
+        android:alpha="0.5" >
 
     <group
-        auto:name="rotationGroup"
-        auto:pivotX="300.0"
-        auto:pivotY="300.0"
-        auto:rotation="45.0" >
+        android:name="rotationGroup"
+        android:pivotX="300.0"
+        android:pivotY="300.0"
+        android:rotation="45.0" >
         <path
-            auto:name="pie1"
-            auto:fillColor="#00000000"
-            auto:pathData="M300,70 a230,230 0 1,0 1,0 z"
-            auto:strokeColor="#FF777777"
-            auto:strokeWidth="70"
-            auto:trimPathEnd=".75"
-            auto:trimPathOffset="0"
-            auto:trimPathStart="0" />
+            android:name="pie1"
+            android:fillColor="#00000000"
+            android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+            android:strokeColor="#FF777777"
+            android:strokeWidth="70"
+            android:trimPathEnd=".75"
+            android:trimPathOffset="0"
+            android:trimPathStart="0" />
         <path
-            auto:name="v"
-            auto:fillColor="#000000"
-            auto:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
+            android:name="v"
+            android:fillColor="#000000"
+            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
 
         <group
-            auto:name="translateToCenterGroup"
-            auto:rotation="0.0"
-            auto:translateX="200.0"
-            auto:translateY="200.0" >
+            android:name="translateToCenterGroup"
+            android:rotation="0.0"
+            android:translateX="200.0"
+            android:translateY="200.0" >
             <group
-                auto:name="rotationGroup2"
-                auto:pivotX="0.0"
-                auto:pivotY="0.0"
-                auto:rotation="-45.0" >
+                android:name="rotationGroup2"
+                android:pivotX="0.0"
+                android:pivotY="0.0"
+                android:rotation="-45.0" >
                 <path
-                    auto:name="twoLines1"
-                    auto:pathData="@string/twoLinePathData"
-                    auto:strokeColor="#FFFF0000"
-                    auto:strokeWidth="20" />
+                    android:name="twoLines1"
+                    android:pathData="@string/twoLinePathData"
+                    android:strokeColor="#FFFF0000"
+                    android:strokeWidth="20" />
 
                 <group
-                    auto:name="translateGroupHalf"
-                    auto:translateX="65.0"
-                    auto:translateY="80.0" >
+                    android:name="translateGroupHalf"
+                    android:translateX="65.0"
+                    android:translateY="80.0" >
                     <group
-                        auto:name="rotationGroup3"
-                        auto:pivotX="-65.0"
-                        auto:pivotY="-80.0"
-                        auto:rotation="-45.0" >
+                        android:name="rotationGroup3"
+                        android:pivotX="-65.0"
+                        android:pivotY="-80.0"
+                        android:rotation="-45.0" >
                         <path
-                            auto:name="twoLines2"
-                            auto:fillColor="#FF00FF00"
-                            auto:pathData="@string/twoLinePathData"
-                            auto:strokeColor="#FF00FF00"
-                            auto:strokeWidth="20" />
+                            android:name="twoLines2"
+                            android:fillColor="#FF00FF00"
+                            android:pathData="@string/twoLinePathData"
+                            android:strokeColor="#FF00FF00"
+                            android:strokeWidth="20" />
 
                         <group
-                            auto:name="translateGroup"
-                            auto:translateX="65.0"
-                            auto:translateY="80.0" >
+                            android:name="translateGroup"
+                            android:translateX="65.0"
+                            android:translateY="80.0" >
                             <group
-                                auto:name="rotationGroupBlue"
-                                auto:pivotX="-65.0"
-                                auto:pivotY="-80.0"
-                                auto:rotation="-45.0" >
+                                android:name="rotationGroupBlue"
+                                android:pivotX="-65.0"
+                                android:pivotY="-80.0"
+                                android:rotation="-45.0" >
                                 <path
-                                    auto:name="twoLines3"
-                                    auto:pathData="@string/twoLinePathData"
-                                    auto:strokeColor="#FF0000FF"
-                                    auto:strokeWidth="20" />
+                                    android:name="twoLines3"
+                                    android:pathData="@string/twoLinePathData"
+                                    android:strokeColor="#FF0000FF"
+                                    android:strokeWidth="20" />
                             </group>
                         </group>
                     </group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
index 43fc7ea..097e028 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
@@ -14,25 +14,24 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="400"
-        auto:viewportWidth="600" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="600" >
 
     <group>
         <path
-            auto:name="pie1"
-            auto:fillColor="#ffffffff"
-            auto:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeWidth="1" />
+            android:name="pie1"
+            android:fillColor="#ffffffff"
+            android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+            android:strokeColor="#FF00FF00"
+            android:strokeWidth="1" />
         <path
-            auto:name="half"
-            auto:fillColor="#FFFF0000"
-            auto:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
-            auto:strokeColor="#FF0000FF"
-            auto:strokeWidth="5" />
+            android:name="half"
+            android:fillColor="#FFFF0000"
+            android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+            android:strokeColor="#FF0000FF"
+            android:strokeWidth="5" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
index 5b4fdd1..102ae7a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
@@ -14,26 +14,25 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="500"
-        auto:viewportWidth="800" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="500"
+        android:viewportWidth="800" >
 
     <group
-        auto:pivotX="90"
-        auto:pivotY="100"
-        auto:rotation="20">
+        android:pivotX="90"
+        android:pivotY="100"
+        android:rotation="20">
         <path
-            auto:name="pie2"
-            auto:pathData="M200,350 l 50,-25
+            android:name="pie2"
+            android:pathData="M200,350 l 50,-25
            a25,12 -30 0,1 100,-50 l 50,-25
            a25,25 -30 0,1 100,-50 l 50,-25
            a25,37 -30 0,1 100,-50 l 50,-25
            a25,50 -30 0,1 100,-50 l 50,-25"
-            auto:fillColor="#00000000"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeWidth="10" />
+            android:fillColor="#00000000"
+            android:strokeColor="#FF00FF00"
+            android:strokeWidth="10" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
index f4ef87f..bdfcf81 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
@@ -14,22 +14,21 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="400"
-        auto:viewportWidth="500" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="500" >
 
     <group
-        auto:pivotX="250"
-        auto:pivotY="200"
-        auto:rotation="180">
+        android:pivotX="250"
+        android:pivotY="200"
+        android:rotation="180">
         <path
-            auto:name="house"
-            auto:fillColor="#ff440000"
-            auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            auto:strokeColor="#FFFF0000"
-            auto:strokeWidth="10" />
+            android:name="house"
+            android:fillColor="#ff440000"
+            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+            android:strokeColor="#FFFF0000"
+            android:strokeWidth="10" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
index 0c64bca..ed1efa0 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
@@ -14,35 +14,34 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="200"
-        auto:viewportWidth="200" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="200"
+        android:viewportWidth="200" >
 
     <group>
         <path
-            auto:name="background1"
-            auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
-            auto:fillColor="#FF000000"/>
+            android:name="background1"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+            android:fillColor="#FF000000"/>
         <path
-            auto:name="background2"
-            auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
-            auto:fillColor="#FF000000"/>
+            android:name="background2"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+            android:fillColor="#FF000000"/>
     </group>
     <group
-        auto:pivotX="100"
-        auto:pivotY="100"
-        auto:rotation="90"
-        auto:scaleX="0.75"
-        auto:scaleY="0.5"
-        auto:translateX="0.0"
-        auto:translateY="100.0">
+        android:pivotX="100"
+        android:pivotY="100"
+        android:rotation="90"
+        android:scaleX="0.75"
+        android:scaleY="0.5"
+        android:translateX="0.0"
+        android:translateY="100.0">
         <path
-            auto:name="twoLines"
-            auto:pathData="M 100,10 v 90 M 10,100 h 90"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeWidth="10" />
+            android:name="twoLines"
+            android:pathData="M 100,10 v 90 M 10,100 h 90"
+            android:strokeColor="#FF00FF00"
+            android:strokeWidth="10" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
index 28cf09a..ba15f41 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
@@ -13,18 +13,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-            auto:width="64dp"
-            auto:height="64dp" auto:viewportWidth="1200"
-          auto:viewportHeight="600">
+            android:width="64dp"
+            android:height="64dp" android:viewportWidth="1200"
+          android:viewportHeight="600">
 
     <group>
         <path
-                auto:name="house"
-                auto:pathData="M200,300 Q400,50 600,300 T1000,300"
-                auto:fillColor="#00000000"
-                auto:strokeColor="#FFFF0000"
-                auto:strokeWidth="10"/>
+                android:name="house"
+                android:pathData="M200,300 Q400,50 600,300 T1000,300"
+                android:fillColor="#00000000"
+                android:strokeColor="#FFFF0000"
+                android:strokeWidth="10"/>
     </group>
 
 </vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
index d66d4ff..ee2122a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
@@ -14,19 +14,18 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="400"
-        auto:viewportWidth="500" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="500" >
 
     <group>
         <path
-            auto:name="house"
-            auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            auto:fillColor="#00000000"
-            auto:strokeColor="#FFFFFF00"
-            auto:strokeWidth="10" />
+            android:name="house"
+            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+            android:fillColor="#00000000"
+            android:strokeColor="#FFFFFF00"
+            android:strokeWidth="10" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
index 3a6559d..b98e1de 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
@@ -14,21 +14,20 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="800"
-        auto:viewportWidth="1000" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="800"
+        android:viewportWidth="1000" >
 
     <group>
         <path
-            auto:name="house"
-            auto:pathData="M10,300 Q400,550 600,300 T1000,300"
-            auto:pivotX="90"
-            auto:pivotY="100"
-            auto:fillColor="#00000000"
-            auto:strokeColor="#FFFF0000"
-            auto:strokeWidth="60" />
+            android:name="house"
+            android:pathData="M10,300 Q400,550 600,300 T1000,300"
+            android:pivotX="90"
+            android:pivotY="100"
+            android:fillColor="#00000000"
+            android:strokeColor="#FFFF0000"
+            android:strokeWidth="60" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
index d6fd704..1c86818 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
@@ -14,22 +14,21 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="480"
-        auto:viewportWidth="480" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="480"
+        android:viewportWidth="480" >
 
     <group>
         <path
-            auto:name="edit"
-            auto:fillColor="#FF00FFFF"
-            auto:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+            android:name="edit"
+            android:fillColor="#FF00FFFF"
+            android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
     c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
     c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
     c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
-            auto:strokeColor="#FF000000"
-            auto:strokeWidth="10" />
+            android:strokeColor="#FF000000"
+            android:strokeWidth="10" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
index 9136b73..247f6bc 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
@@ -14,35 +14,34 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="200"
-        auto:viewportWidth="200" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="200"
+        android:viewportWidth="200" >
 
     <group>
         <path
-            auto:name="background1"
-            auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
-            auto:fillColor="#FF000000"/>
+            android:name="background1"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+            android:fillColor="#FF000000"/>
         <path
-            auto:name="background2"
-            auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
-            auto:fillColor="#FF000000"/>
+            android:name="background2"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+            android:fillColor="#FF000000"/>
     </group>
     <group
-        auto:pivotX="0"
-        auto:pivotY="0"
-        auto:rotation="90"
-        auto:scaleX="0.75"
-        auto:scaleY="0.5"
-        auto:translateX="100.0"
-        auto:translateY="100.0">
+        android:pivotX="0"
+        android:pivotY="0"
+        android:rotation="90"
+        android:scaleX="0.75"
+        android:scaleY="0.5"
+        android:translateX="100.0"
+        android:translateY="100.0">
         <path
-            auto:name="twoLines"
-            auto:pathData="M 100,10 v 90 M 10,100 h 90"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeWidth="10" />
+            android:name="twoLines"
+            android:pathData="M 100,10 v 90 M 10,100 h 90"
+            android:strokeColor="#FF00FF00"
+            android:strokeWidth="10" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
index 2b33a89..39d891f 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
@@ -14,53 +14,52 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="400"
-        auto:viewportWidth="400" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
 
-    <group auto:name="backgroundGroup" >
+    <group android:name="backgroundGroup" >
         <path
-            auto:name="background1"
-            auto:fillColor="#80000000"
-            auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+            android:name="background1"
+            android:fillColor="#80000000"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
         <path
-            auto:name="background2"
-            auto:fillColor="#80000000"
-            auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+            android:name="background2"
+            android:fillColor="#80000000"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
     </group>
     <group
-        auto:name="translateToCenterGroup"
-        auto:translateX="50.0"
-        auto:translateY="90.0" >
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
         <path
-            auto:name="twoLines"
-            auto:pathData="M 0,0 v 100 M 0,0 h 100"
-            auto:strokeColor="#FFFF0000"
-            auto:strokeWidth="20" />
+            android:name="twoLines"
+            android:pathData="M 0,0 v 100 M 0,0 h 100"
+            android:strokeColor="#FFFF0000"
+            android:strokeWidth="20" />
 
         <group
-            auto:name="rotationGroup"
-            auto:pivotX="0.0"
-            auto:pivotY="0.0"
-            auto:rotation="-45.0" >
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0" >
             <path
-                auto:name="twoLines1"
-                auto:pathData="M 0,0 v 100 M 0,0 h 100"
-                auto:strokeColor="#FF00FF00"
-                auto:strokeWidth="20" />
+                android:name="twoLines1"
+                android:pathData="M 0,0 v 100 M 0,0 h 100"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="20" />
 
             <group
-                auto:name="translateGroup"
-                auto:translateX="130.0"
-                auto:translateY="160.0" >
-                <group auto:name="scaleGroup" >
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0" >
+                <group android:name="scaleGroup" >
                     <path
-                        auto:name="twoLines2"
-                        auto:pathData="M 0,0 v 100 M 0,0 h 100"
-                        auto:strokeColor="#FF0000FF"
-                        auto:strokeWidth="20" />
+                        android:name="twoLines2"
+                        android:pathData="M 0,0 v 100 M 0,0 h 100"
+                        android:strokeColor="#FF0000FF"
+                        android:strokeWidth="20" />
                 </group>
             </group>
         </group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
index d5759f9..4a1c062 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
@@ -14,67 +14,66 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="400"
-        auto:viewportWidth="400" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
 
-    <group auto:name="backgroundGroup" >
+    <group android:name="backgroundGroup" >
         <path
-            auto:name="background1"
-            auto:fillColor="#80000000"
-            auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+            android:name="background1"
+            android:fillColor="#80000000"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
         <path
-            auto:name="background2"
-            auto:fillColor="#80000000"
-            auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+            android:name="background2"
+            android:fillColor="#80000000"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
     </group>
     <group
-        auto:name="translateToCenterGroup"
-        auto:translateX="50.0"
-        auto:translateY="90.0" >
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
         <path
-            auto:name="twoLines"
-            auto:pathData="@string/twoLinePathData"
-            auto:strokeColor="#FFFF0000"
-            auto:strokeWidth="20" />
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="#FFFF0000"
+            android:strokeWidth="20" />
 
         <group
-            auto:name="rotationGroup"
-            auto:pivotX="0.0"
-            auto:pivotY="0.0"
-            auto:rotation="-45.0" >
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0" >
             <path
-                auto:name="twoLines1"
-                auto:pathData="@string/twoLinePathData"
-                auto:strokeColor="#FF00FF00"
-                auto:strokeWidth="20" />
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="20" />
 
             <group
-                auto:name="translateGroup"
-                auto:translateX="130.0"
-                auto:translateY="160.0" >
-                <group auto:name="scaleGroup" >
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0" >
+                <group android:name="scaleGroup" >
                     <path
-                        auto:name="twoLines3"
-                        auto:pathData="@string/twoLinePathData"
-                        auto:strokeColor="#FF0000FF"
-                        auto:strokeWidth="20" />
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="#FF0000FF"
+                        android:strokeWidth="20" />
                 </group>
             </group>
 
             <group
-                auto:name="translateGroupHalf"
-                auto:translateX="65.0"
-                auto:translateY="80.0" >
-                <group auto:name="scaleGroup" >
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0" >
+                <group android:name="scaleGroup" >
                     <path
-                        auto:name="twoLines2"
-                        auto:pathData="@string/twoLinePathData"
-                        auto:fillColor="#FFFFFFFF"
-                        auto:strokeColor="#FFFFFFFF"
-                        auto:strokeWidth="20" />
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:fillColor="?android:attr/colorForeground"
+                        android:strokeColor="?android:attr/colorForeground"
+                        android:strokeWidth="20" />
                 </group>
             </group>
         </group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
index b054692..a7a8bd3 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
@@ -14,67 +14,66 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="400"
-        auto:viewportWidth="400" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
 
-    <group auto:name="backgroundGroup">
+    <group android:name="backgroundGroup">
         <path
-            auto:name="background1"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
         <path
-            auto:name="background2"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
     </group>
     <group
-        auto:name="translateToCenterGroup"
-        auto:translateX="50.0"
-        auto:translateY="90.0" >
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
         <path
-            auto:name="twoLines"
-            auto:pathData="@string/twoLinePathData"
-            auto:strokeColor="#FFFF0000"
-            auto:strokeWidth="20" />
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="#FFFF0000"
+            android:strokeWidth="20" />
 
         <group
-            auto:name="rotationGroup"
-            auto:pivotX="0.0"
-            auto:pivotY="0.0"
-            auto:rotation="-45.0">
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0">
             <path
-                auto:name="twoLines1"
-                auto:pathData="@string/twoLinePathData"
-                auto:strokeColor="#FF00FF00"
-                auto:strokeWidth="20" />
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="20" />
 
             <group
-                auto:name="translateGroup"
-                auto:translateX="130.0"
-                auto:translateY="160.0">
-                <group auto:name="scaleGroup" >
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0">
+                <group android:name="scaleGroup" >
                     <path
-                        auto:name="twoLines3"
-                        auto:pathData="@string/twoLinePathData"
-                        auto:strokeColor="#FF0000FF"
-                        auto:strokeWidth="20" />
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="#FF0000FF"
+                        android:strokeWidth="20" />
                 </group>
             </group>
 
             <group
-                auto:name="translateGroupHalf"
-                auto:translateX="65.0"
-                auto:translateY="80.0">
-                <group auto:name="scaleGroup" >
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0">
+                <group android:name="scaleGroup" >
                     <path
-                        auto:name="twoLines2"
-                        auto:pathData="@string/twoLinePathData"
-                        auto:fillColor="#FFFFFFFF"
-                        auto:strokeColor="#FFFFFFFF"
-                        auto:strokeWidth="20" />
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:fillColor="?android:attr/colorForeground"
+                        android:strokeColor="?android:attr/colorForeground"
+                        android:strokeWidth="20" />
                 </group>
             </group>
         </group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
index 7a94ed6..7c9e771 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
@@ -14,70 +14,69 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="64dp"
-        auto:width="64dp"
-        auto:viewportHeight="400"
-        auto:viewportWidth="400" >
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
 
     <group
-        auto:name="FirstLevelGroup"
-        auto:translateX="100.0"
-        auto:translateY="0.0" >
+        android:name="FirstLevelGroup"
+        android:translateX="100.0"
+        android:translateY="0.0" >
         <group
-            auto:name="SecondLevelGroup1"
-            auto:translateX="-100.0"
-            auto:translateY="50.0" >
+            android:name="SecondLevelGroup1"
+            android:translateX="-100.0"
+            android:translateY="50.0" >
             <path
-                auto:fillColor="#FF00FF00"
-                auto:pathData="@string/rectangle200" />
+                android:fillColor="#FF00FF00"
+                android:pathData="@string/rectangle200" />
 
             <group
-                auto:name="ThridLevelGroup1"
-                auto:translateX="-100.0"
-                auto:translateY="50.0" >
+                android:name="ThridLevelGroup1"
+                android:translateX="-100.0"
+                android:translateY="50.0" >
                 <path
-                    auto:fillColor="#FF0000FF"
-                    auto:pathData="@string/rectangle200" />
+                    android:fillColor="#FF0000FF"
+                    android:pathData="@string/rectangle200" />
             </group>
             <group
-                auto:name="ThridLevelGroup2"
-                auto:translateX="100.0"
-                auto:translateY="50.0" >
+                android:name="ThridLevelGroup2"
+                android:translateX="100.0"
+                android:translateY="50.0" >
                 <path
-                    auto:fillColor="#FF000000"
-                    auto:pathData="@string/rectangle200" />
+                    android:fillColor="#FF000000"
+                    android:pathData="@string/rectangle200" />
             </group>
         </group>
         <group
-            auto:name="SecondLevelGroup2"
-            auto:translateX="100.0"
-            auto:translateY="50.0" >
+            android:name="SecondLevelGroup2"
+            android:translateX="100.0"
+            android:translateY="50.0" >
             <path
-                auto:fillColor="#FF0000FF"
-                auto:pathData="@string/rectangle200" />
+                android:fillColor="#FF0000FF"
+                android:pathData="@string/rectangle200" />
 
             <group
-                auto:name="ThridLevelGroup3"
-                auto:translateX="-100.0"
-                auto:translateY="50.0" >
+                android:name="ThridLevelGroup3"
+                android:translateX="-100.0"
+                android:translateY="50.0" >
                 <path
-                    auto:fillColor="#FFFF0000"
-                    auto:pathData="@string/rectangle200" />
+                    android:fillColor="#FFFF0000"
+                    android:pathData="@string/rectangle200" />
             </group>
             <group
-                auto:name="ThridLevelGroup4"
-                auto:translateX="100.0"
-                auto:translateY="50.0" >
+                android:name="ThridLevelGroup4"
+                android:translateX="100.0"
+                android:translateY="50.0" >
                 <path
-                    auto:fillColor="#FF00FF00"
-                    auto:pathData="@string/rectangle200" />
+                    android:fillColor="#FF00FF00"
+                    android:pathData="@string/rectangle200" />
             </group>
         </group>
 
         <path
-            auto:fillColor="#FFFF0000"
-            auto:pathData="@string/rectangle200" />
+            android:fillColor="#FFFF0000"
+            android:pathData="@string/rectangle200" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
index b2dd4a3..eda06d8 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
@@ -14,33 +14,32 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:height="64dp"
-    auto:viewportHeight="200"
-    auto:viewportWidth="200"
-    auto:width="64dp" >
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
 
     <group>
         <path
-            auto:name="background1"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
         <path
-            auto:name="background2"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
     </group>
     <group
-        auto:translateX="50"
-        auto:translateY="50" >
+        android:translateX="50"
+        android:translateY="50" >
         <path
-            auto:name="twoLines"
-            auto:pathData="M 100,20 l 0 80 l -30 -80"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeLineCap="butt"
-            auto:strokeLineJoin="miter"
-            auto:strokeMiterLimit="5"
-            auto:strokeWidth="20" />
+            android:name="twoLines"
+            android:pathData="M 100,20 l 0 80 l -30 -80"
+            android:strokeColor="#FF00FF00"
+            android:strokeLineCap="butt"
+            android:strokeLineJoin="miter"
+            android:strokeMiterLimit="5"
+            android:strokeWidth="20" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
index b8f88ce..cd46dd9 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
@@ -14,33 +14,32 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:height="64dp"
-    auto:viewportHeight="200"
-    auto:viewportWidth="200"
-    auto:width="64dp" >
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
 
     <group>
         <path
-            auto:name="background1"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
         <path
-            auto:name="background2"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
     </group>
     <group
-        auto:translateX="50"
-        auto:translateY="50" >
+        android:translateX="50"
+        android:translateY="50" >
         <path
-            auto:name="twoLines"
-            auto:pathData="M 100,20 l 0 80 l -30 -80"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeLineCap="round"
-            auto:strokeLineJoin="round"
-            auto:strokeMiterLimit="10"
-            auto:strokeWidth="20" />
+            android:name="twoLines"
+            android:pathData="M 100,20 l 0 80 l -30 -80"
+            android:strokeColor="#FF00FF00"
+            android:strokeLineCap="round"
+            android:strokeLineJoin="round"
+            android:strokeMiterLimit="10"
+            android:strokeWidth="20" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
index 30c7fce..812af6b 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
@@ -14,34 +14,33 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-    auto:height="64dp"
-    auto:viewportHeight="200"
-    auto:viewportWidth="200"
-    auto:width="64dp"
-    auto:autoMirrored="true" >
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp"
+    android:autoMirrored="true" >
 
     <group>
         <path
-            auto:name="background1"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
         <path
-            auto:name="background2"
-            auto:fillColor="#FF000000"
-            auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
     </group>
     <group
-        auto:translateX="50"
-        auto:translateY="50" >
+        android:translateX="50"
+        android:translateY="50" >
         <path
-            auto:name="twoLines"
-            auto:pathData="M 100,20 l 0 80 l -30 -80"
-            auto:strokeColor="#FF00FF00"
-            auto:strokeLineCap="square"
-            auto:strokeLineJoin="bevel"
-            auto:strokeMiterLimit="10"
-            auto:strokeWidth="20" />
+            android:name="twoLines"
+            android:pathData="M 100,20 l 0 80 l -30 -80"
+            android:strokeColor="#FF00FF00"
+            android:strokeLineCap="square"
+            android:strokeLineJoin="bevel"
+            android:strokeMiterLimit="10"
+            android:strokeWidth="20" />
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
index 2ac1d42..b24d31c 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
@@ -14,16 +14,15 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="48dp"
-        auto:width="48dp"
-        auto:viewportHeight="1"
-        auto:viewportWidth="1" >
+        android:height="48dp"
+        android:width="48dp"
+        android:viewportHeight="1"
+        android:viewportWidth="1" >
 
     <group>
         <path
-            auto:name="box1"
-            auto:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
-            auto:fillColor="#ff00ff00"/>
+            android:name="box1"
+            android:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
+            android:fillColor="#ff00ff00"/>
     </group>
 </vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
index 6abb455..24f7372 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
@@ -14,16 +14,15 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:auto="http://schemas.android.com/apk/res-auto"
-        auto:height="48dp"
-        auto:width="48dp"
-        auto:viewportHeight="48"
-        auto:viewportWidth="48" >
+        android:height="48dp"
+        android:width="48dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48" >
 
     <group>
         <path
-            auto:name="plus1"
-            auto:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
-            auto:fillColor="#ff00ff00"/>
+            android:name="plus1"
+            android:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
+            android:fillColor="#ff00ff00"/>
     </group>
 </vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml
new file mode 100644
index 0000000..828f0d9
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml
@@ -0,0 +1,57 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="@color/color0"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="@color/color2"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:pivotX="0"
+        android:pivotY="0"
+        android:rotation="90" >
+        <group
+            android:scaleX="1.5"
+            android:scaleY="1" >
+            <group
+                android:pivotX="0"
+                android:pivotY="0"
+                android:rotation="-90" >
+                <group
+                    android:scaleX="1.5"
+                    android:scaleY="1" >
+                    <path
+                        android:name="twoLines"
+                        android:fillColor="#FFFF0000"
+                        android:pathData="@string/triangle100"
+                        android:strokeColor="#FF00FF00"
+                        android:strokeWidth="10" />
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml
new file mode 100644
index 0000000..530c73b
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="-1"
+        android:scaleY="-1" >
+        <group
+            android:scaleX="-1"
+            android:scaleY="-1" >
+            <group
+                android:pivotX="100"
+                android:pivotY="100"
+                android:rotation="45" >
+                <path
+                    android:name="twoLines"
+                    android:fillColor="#FFFF0000"
+                    android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                    android:strokeColor="#FF00FF00"
+                    android:strokeWidth="10" />
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml
new file mode 100644
index 0000000..200eb61
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml
@@ -0,0 +1,48 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="2"
+        android:scaleY="0.5" >
+        <group
+            android:pivotX="100"
+            android:pivotY="100"
+            android:rotation="45" >
+            <path
+                android:name="twoLines"
+                android:fillColor="#FFFF0000"
+                android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="10" />
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml
new file mode 100644
index 0000000..a40fc9c2
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml
@@ -0,0 +1,62 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:pivotX="0"
+        android:pivotY="0"
+        android:rotation="45" >
+        <group
+            android:pivotX="0"
+            android:pivotY="0"
+            android:rotation="90" >
+            <group
+                android:scaleX="1.5"
+                android:scaleY="1" >
+                <group
+                    android:pivotX="0"
+                    android:pivotY="0"
+                    android:rotation="-90" >
+                    <group
+                        android:scaleX="1.5"
+                        android:scaleY="1" >
+                        <path
+                            android:name="twoLines"
+                            android:fillColor="#FFFF0000"
+                            android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                            android:strokeColor="#FF00FF00"
+                            android:strokeWidth="10" />
+                    </group>
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_test01.xml b/graphics/drawable/teststatic/res/drawable/vector_test01.xml
new file mode 100644
index 0000000..8b891d6
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_test01.xml
@@ -0,0 +1,31 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="128dp"
+        android:width="128dp"
+        android:viewportHeight="512"
+        android:viewportWidth="512" >
+
+    <group>
+        <path
+            android:name="002b"
+            android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
+            android:strokeColor="#FF0000FF"
+            android:strokeWidth="4"
+            android:fillColor="#00000000" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_test02.xml b/graphics/drawable/teststatic/res/drawable/vector_test02.xml
new file mode 100644
index 0000000..e0af323
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_test02.xml
@@ -0,0 +1,31 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="128dp"
+        android:width="128dp"
+        android:viewportHeight="512"
+        android:viewportWidth="512" >
+
+    <group>
+        <path
+            android:name="002b"
+            android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
+            android:strokeColor="#FF0000FF"
+            android:strokeWidth="4"
+            android:fillColor="#00000000" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/graphics/drawable/teststatic/res/values/colors.xml
similarity index 69%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to graphics/drawable/teststatic/res/values/colors.xml
index a4614f6..6eb3036 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/graphics/drawable/teststatic/res/values/colors.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -13,7 +12,9 @@
      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:drawable="@drawable/ic_setting_light" />
-</selector>
+<resources>
+    <color name="color0">#a6e4ea</color>
+    <color name="color1">#ff3838</color>
+    <color name="color2">#ffff51</color>
+    <color name="color3">#0ed300</color>
+</resources>
diff --git a/graphics/drawable/teststatic/res/values/strings.xml b/graphics/drawable/teststatic/res/values/strings.xml
index c5451c88..065e7d9 100644
--- a/graphics/drawable/teststatic/res/values/strings.xml
+++ b/graphics/drawable/teststatic/res/values/strings.xml
@@ -25,4 +25,5 @@
     <string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string>
     <string name="heart">    "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string>
     <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
-</resources>
\ No newline at end of file
+    <string name="triangle100">"M 100, 0 l 0, 100, -100, 0 z"</string>
+</resources>
diff --git a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
index 8bb766e5..c92ff47 100644
--- a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
+++ b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
@@ -34,6 +34,10 @@
 
     private static final String LOGCAT = "VectorDrawable1";
     protected int[] icon = {
+            R.drawable.vector_drawable_scale0,
+            R.drawable.vector_drawable_scale1,
+            R.drawable.vector_drawable_scale2,
+            R.drawable.vector_drawable_scale3,
             R.drawable.vector_drawable01,
             R.drawable.vector_drawable02,
             R.drawable.vector_drawable03,
@@ -64,6 +68,8 @@
             R.drawable.vector_drawable28,
             R.drawable.vector_drawable29,
             R.drawable.vector_drawable30,
+            R.drawable.vector_test01,
+            R.drawable.vector_test02
     };
 
     private static final int EXTRA_TESTS = 2;
@@ -85,8 +91,10 @@
         time =  android.os.SystemClock.currentThreadTimeMillis()-time;
 
         // Testing Tint on one particular case.
-        d[3].setTint(0x8000FF00);
-        d[3].setTintMode(Mode.MULTIPLY);
+        if (d.length > 3) {
+            d[3].setTint(0x8000FF00);
+            d[3].setTintMode(Mode.MULTIPLY);
+        }
 
         // Testing Constant State like operation by creating the first 2 icons
         // from the 3rd one's constant state.
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java b/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java
new file mode 100644
index 0000000..e6b2e14
--- /dev/null
+++ b/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package android.support.graphics.drawable;
+
+public class AndroidResources {
+
+    // Resources ID generated in the latest R.java for framework.
+    static final int[] styleable_VectorDrawableTypeArray = {
+            android.R.attr.name, android.R.attr.tint, android.R.attr.height,
+            android.R.attr.width, android.R.attr.alpha, android.R.attr.autoMirrored,
+            android.R.attr.mode, android.R.attr.viewportWidth, android.R.attr.viewportHeight
+    };
+    static final int styleable_VectorDrawable_alpha = 4;
+    static final int styleable_VectorDrawable_autoMirrored = 5;
+    static final int styleable_VectorDrawable_height = 2;
+    static final int styleable_VectorDrawable_name = 0;
+    static final int styleable_VectorDrawable_tint = 1;
+    static final int styleable_VectorDrawable_Mode = 6;
+    static final int styleable_VectorDrawable_viewportHeight = 8;
+    static final int styleable_VectorDrawable_viewportWidth = 7;
+    static final int styleable_VectorDrawable_width = 3;
+    static final int[] styleable_VectorDrawableGroup = {
+            android.R.attr.name, android.R.attr.pivotX, android.R.attr.pivotY,
+            android.R.attr.scaleX, android.R.attr.scaleY, android.R.attr.rotation,
+            android.R.attr.translateX, android.R.attr.translateY
+    };
+    static final int styleable_VectorDrawableGroup_name = 0;
+    static final int styleable_VectorDrawableGroup_pivotX = 1;
+    static final int styleable_VectorDrawableGroup_pivotY = 2;
+    static final int styleable_VectorDrawableGroup_rotation = 5;
+    static final int styleable_VectorDrawableGroup_scaleX = 3;
+    static final int styleable_VectorDrawableGroup_scaleY = 4;
+    static final int styleable_VectorDrawableGroup_translateX = 6;
+    static final int styleable_VectorDrawableGroup_translateY = 7;
+    static final int[] styleable_VectorDrawablePath = {
+            android.R.attr.name, android.R.attr.fillColor, android.R.attr.pathData,
+            android.R.attr.strokeColor, android.R.attr.strokeWidth, android.R.attr.trimPathStart,
+            android.R.attr.trimPathEnd, android.R.attr.trimPathOffset, android.R.attr.strokeLineCap,
+            android.R.attr.strokeLineJoin, android.R.attr.strokeMiterLimit,
+            android.R.attr.strokeAlpha, android.R.attr.fillAlpha
+    };
+    static final int styleable_VectorDrawablePath_fillAlpha = 12;
+    static final int styleable_VectorDrawablePath_fillColor = 1;
+    static final int styleable_VectorDrawablePath_name = 0;
+    static final int styleable_VectorDrawablePath_pathData = 2;
+    static final int styleable_VectorDrawablePath_strokeAlpha = 11;
+    static final int styleable_VectorDrawablePath_strokeColor = 3;
+    static final int styleable_VectorDrawablePath_strokeLineCap = 8;
+    static final int styleable_VectorDrawablePath_strokeLineJoin = 9;
+    static final int styleable_VectorDrawablePath_strokeMiterLimit = 10;
+    static final int styleable_VectorDrawablePath_strokeWidth = 4;
+    static final int styleable_VectorDrawablePath_trimPathEnd = 6;
+    static final int styleable_VectorDrawablePath_trimPathOffset = 7;
+    static final int styleable_VectorDrawablePath_trimPathStart = 5;
+    static final int[] styleable_VectorDrawableClipPath = {
+            android.R.attr.name, android.R.attr.pathData
+    };
+    static final int styleable_VectorDrawableClipPath_name = 0;
+    static final int styleable_VectorDrawableClipPath_pathData = 1;
+
+    static final int[] styleable_AnimatedVectorDrawable = {
+            android.R.attr.drawable
+    };
+    static final int styleable_AnimatedVectorDrawable_drawable = 0;
+    static final int[] styleable_AnimatedVectorDrawableTarget = {
+            android.R.attr.name, android.R.attr.animation
+    };
+    static final int styleable_AnimatedVectorDrawableTarget_animation = 1;
+    static final int styleable_AnimatedVectorDrawableTarget_name = 0;
+}
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java b/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java
new file mode 100644
index 0000000..161eae6
--- /dev/null
+++ b/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package android.support.graphics.drawable;
+
+import android.content.res.TypedArray;
+import org.xmlpull.v1.XmlPullParser;
+
+
+public class TypedArrayUtils {
+    private static final String NAMESPACE = "http://schemas.android.com/apk/res/android";
+
+    public static boolean hasAttribute(XmlPullParser parser, String attrName) {
+        return parser.getAttributeValue(NAMESPACE, attrName) != null;
+    }
+
+    public static float getNamedFloat(TypedArray a, XmlPullParser parser, String attrName,
+                                      int resId, float defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getFloat(resId, defaultValue);
+        }
+    }
+
+    public static boolean getNamedBoolean(TypedArray a, XmlPullParser parser, String attrName,
+                                      int resId, boolean defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getBoolean(resId, defaultValue);
+        }
+    }
+
+    public static int getNamedInt(TypedArray a, XmlPullParser parser, String attrName,
+                                          int resId, int defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getInt(resId, defaultValue);
+        }
+    }
+
+    public static int getNamedColor(TypedArray a, XmlPullParser parser, String attrName,
+                                        int resId, int defaultValue) {
+        final boolean hasAttr = hasAttribute(parser, attrName);
+        if (!hasAttr) {
+            return defaultValue;
+        } else {
+            return a.getColor(resId, defaultValue);
+        }
+    }
+}
diff --git a/local.properties b/local.properties
index 5b31c8a..8aea008 100644
--- a/local.properties
+++ b/local.properties
@@ -1 +1,11 @@
-android.dir=../../
\ No newline at end of file
+## This file is automatically generated by Android Studio.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Fri Aug 21 16:47:26 KST 2015
+android.dir=../../
diff --git a/percent/api/23.txt b/percent/api/23.0.0.txt
similarity index 100%
rename from percent/api/23.txt
rename to percent/api/23.0.0.txt
diff --git a/percent/api/23.1.0.txt b/percent/api/23.1.0.txt
new file mode 100644
index 0000000..eb10df8
--- /dev/null
+++ b/percent/api/23.1.0.txt
@@ -0,0 +1,65 @@
+package android.support.percent {
+
+  public class PercentFrameLayout extends android.widget.FrameLayout {
+    ctor public PercentFrameLayout(android.content.Context);
+    ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public static class PercentFrameLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+    ctor public PercentFrameLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public PercentFrameLayout.LayoutParams(int, int);
+    ctor public PercentFrameLayout.LayoutParams(int, int, int);
+    ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    ctor public PercentFrameLayout.LayoutParams(android.support.percent.PercentFrameLayout.LayoutParams);
+    method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+  public class PercentLayoutHelper {
+    ctor public PercentLayoutHelper(android.view.ViewGroup);
+    method public void adjustChildren(int, int);
+    method public static void fetchWidthAndHeight(android.view.ViewGroup.LayoutParams, android.content.res.TypedArray, int, int);
+    method public static android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo(android.content.Context, android.util.AttributeSet);
+    method public boolean handleMeasuredStateTooSmall();
+    method public void restoreOriginalParams();
+  }
+
+  public static class PercentLayoutHelper.PercentLayoutInfo {
+    ctor public PercentLayoutHelper.PercentLayoutInfo();
+    method public void fillLayoutParams(android.view.ViewGroup.LayoutParams, int, int);
+    method public void fillMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams, int, int);
+    method public void restoreLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public void restoreMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    field public float aspectRatio;
+    field public float bottomMarginPercent;
+    field public float endMarginPercent;
+    field public float heightPercent;
+    field public float leftMarginPercent;
+    field public float rightMarginPercent;
+    field public float startMarginPercent;
+    field public float topMarginPercent;
+    field public float widthPercent;
+  }
+
+  public static abstract interface PercentLayoutHelper.PercentLayoutParams {
+    method public abstract android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+  public class PercentRelativeLayout extends android.widget.RelativeLayout {
+    ctor public PercentRelativeLayout(android.content.Context);
+    ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet);
+    ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public static class PercentRelativeLayout.LayoutParams extends android.widget.RelativeLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+    ctor public PercentRelativeLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public PercentRelativeLayout.LayoutParams(int, int);
+    ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+  }
+
+}
+
diff --git a/percent/build.gradle b/percent/build.gradle
index 28907b8..6fbc478 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -28,3 +28,70 @@
         targetCompatibility JavaVersion.VERSION_1_7
     }
 }
+
+android.libraryVariants.all { variant ->
+    def name = variant.buildType.name
+
+    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
+        return; // Skip debug builds.
+    }
+    def suffix = name.capitalize()
+
+    def jarTask = project.tasks.create(name: "jar${suffix}", type: Jar){
+        dependsOn variant.javaCompile
+        from variant.javaCompile.destinationDir
+        from 'LICENSE.txt'
+    }
+    def javadocTask = project.tasks.create(name: "javadoc${suffix}", type: Javadoc) {
+        source android.sourceSets.main.java
+        classpath = files(variant.javaCompile.classpath.files) + files(
+                "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
+    }
+
+    def javadocJarTask = project.tasks.create(name: "javadocJar${suffix}", type: Jar) {
+        classifier = 'javadoc'
+        from 'build/docs/javadoc'
+    }
+
+    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
+        classifier = 'sources'
+        from android.sourceSets.main.java.srcDirs
+    }
+
+    artifacts.add('archives', javadocJarTask);
+    artifacts.add('archives', sourcesJarTask);
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri(rootProject.ext.supportRepoOut)) {
+            }
+
+            pom.project {
+                name 'Android Percent Support Library'
+                description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 7 or later."
+                url 'http://developer.android.com/tools/extras/support-library.html'
+                inceptionYear '2011'
+
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                        distribution 'repo'
+                    }
+                }
+
+                scm {
+                    url "http://source.android.com"
+                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+                }
+                developers {
+                    developer {
+                        name 'The Android Open Source Project'
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/recommendation/api/23.txt b/recommendation/api/23.0.0.txt
similarity index 100%
rename from recommendation/api/23.txt
rename to recommendation/api/23.0.0.txt
diff --git a/recommendation/api/23.txt b/recommendation/api/23.1.0.txt
similarity index 100%
copy from recommendation/api/23.txt
copy to recommendation/api/23.1.0.txt
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index 0a9ca47..a9db906 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -16,16 +16,19 @@
     sourceSets {
         main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDirs = ['src']
-        main.res.srcDirs = ['res']
+        main.res.srcDir 'res'
+        main.assets.srcDir 'assets'
+        main.resources.srcDir 'src'
+
+        // this moves src/instrumentTest to tests so all folders follow:
+        // tests/java, tests/res, tests/assets, ...
+        // This is a *reset* so it replaces the default paths
+        androidTest.setRoot('tests')
+        androidTest.java.srcDir 'tests/src'
     }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
-
-    lintOptions {
-        // TODO: fix errors and reenable.
-        abortOnError false
-    }
 }
diff --git a/recommendation/src/android/support/app/recommendation/ContentRecommendation.java b/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
index fdc0907..11af02d 100644
--- a/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
+++ b/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
@@ -22,6 +22,8 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 import android.support.annotation.StringDef;
@@ -799,7 +801,7 @@
          * @param iconResourceId An integer id for the badge icon resource.
          * @return The Builder object, for chaining.
          */
-        public Builder setBadgeIcon(int iconResourceId) {
+        public Builder setBadgeIcon(@DrawableRes int iconResourceId) {
             mBuilderBadgeIconId = iconResourceId;
             return this;
         }
@@ -823,7 +825,7 @@
          * @param color An integer value representing the accent color for this recommendation.
          * @return The Builder object, for chaining.
          */
-        public Builder setColor(int color) {
+        public Builder setColor(@ColorInt int color) {
             mBuilderColor = color;
             return this;
         }
diff --git a/scripts/support-deps-license.sh b/scripts/support-deps-license.sh
new file mode 100755
index 0000000..55efac6
--- /dev/null
+++ b/scripts/support-deps-license.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+#
+#  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.
+#
+
+#
+# This needs to be ran from the root folder in the Android source tree
+#
+
+function parentdirname() {
+  FULL_PATH=`readlink -f $1`
+  echo `dirname $FULL_PATH`
+}
+
+function rundeps() {
+  LIB_PATH=$1
+  LIB_PARENT_PATH=`parentdirname $LIB_PATH`
+  OUTPUT_FILE=`basename $LIB_PARENT_PATH`-`basename $LIB_PATH`.log
+  make deps-license PROJ_PATH=$LIB_PATH DEP_PATH=frameworks/support > $OUTPUT_FILE
+}
+
+rundeps frameworks/support/customtabs
+rundeps frameworks/support/design
+rundeps frameworks/support/percent
+rundeps frameworks/support/recommendation
+rundeps frameworks/support/v4
+rundeps frameworks/support/v7/appcompat
+rundeps frameworks/support/v7/cardview
+rundeps frameworks/support/v7/mediarouter
+rundeps frameworks/support/v7/palette
+rundeps frameworks/support/v7/gridlayout
+rundeps frameworks/support/v7/preference
+rundeps frameworks/support/v7/recyclerview
+rundeps frameworks/support/v13
+rundeps frameworks/support/v14/preference
+rundeps frameworks/support/v17/leanback
+rundeps frameworks/support/v17/preference-leanback
diff --git a/settings.gradle b/settings.gradle
index 4c4ac52..d33c2ac 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -48,3 +48,6 @@
 
 include ':support-customtabs'
 project(':support-customtabs').projectDir = new File(rootDir, 'customtabs')
+
+include ':support-recommendation'
+project(':support-recommendation').projectDir = new File(rootDir, 'recommendation')
diff --git a/v13/api/23.txt b/v13/api/23.0.0.txt
similarity index 100%
rename from v13/api/23.txt
rename to v13/api/23.0.0.txt
diff --git a/v13/api/23.txt b/v13/api/23.1.0.txt
similarity index 100%
copy from v13/api/23.txt
copy to v13/api/23.1.0.txt
diff --git a/v14/preference/NOTICES.md b/v14/preference/NOTICES.md
new file mode 100644
index 0000000..a390782
--- /dev/null
+++ b/v14/preference/NOTICES.md
@@ -0,0 +1,11 @@
+# Change Log
+
+## [23.1.0](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/v14/preference) (2015-09-28)
+
+**Breakage and deprecation notices:**
+
+- EditTextPreferenceDialogFragment
+  - onAddEditTextToDialogView has been removed. Any code depending on overriding this method should
+    be moved to onBindDialogView.
+  - The EditText view is now expected to be present in the dialog layout file with the id
+    @android:id/edit, and is no longer created in code.
diff --git a/v14/preference/api/23.txt b/v14/preference/api/23.0.0.txt
similarity index 100%
rename from v14/preference/api/23.txt
rename to v14/preference/api/23.0.0.txt
diff --git a/v14/preference/api/23.1.0.txt b/v14/preference/api/23.1.0.txt
new file mode 100644
index 0000000..fed4623
--- /dev/null
+++ b/v14/preference/api/23.1.0.txt
@@ -0,0 +1,94 @@
+package android.support.v14.preference {
+
+  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public EditTextPreferenceDialogFragment();
+    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public ListPreferenceDialogFragment();
+    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class MultiSelectListPreference extends android.support.v7.preference.DialogPreference {
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
+    ctor public MultiSelectListPreference(android.content.Context);
+    method public int findIndexOfValue(java.lang.String);
+    method public java.lang.CharSequence[] getEntries();
+    method public java.lang.CharSequence[] getEntryValues();
+    method protected boolean[] getSelectedItems();
+    method public java.util.Set<java.lang.String> getValues();
+    method public void setEntries(java.lang.CharSequence[]);
+    method public void setEntries(int);
+    method public void setEntryValues(java.lang.CharSequence[]);
+    method public void setEntryValues(int);
+    method public void setValues(java.util.Set<java.lang.String>);
+  }
+
+  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+    ctor public MultiSelectListPreferenceDialogFragment();
+    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+    ctor public PreferenceDialogFragment();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    method protected void onBindDialogView(android.view.View);
+    method public void onClick(android.content.DialogInterface, int);
+    method protected android.view.View onCreateDialogView(android.content.Context);
+    method public abstract void onDialogClosed(boolean);
+    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
+    field protected static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+    ctor public PreferenceFragment();
+    method public void addPreferencesFromResource(int);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public final android.support.v7.widget.RecyclerView getListView();
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+    method public void setPreferencesFromResource(int, java.lang.String);
+    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
+    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
+    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
+  }
+
+  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchPreference(android.content.Context);
+    method public java.lang.CharSequence getSwitchTextOff();
+    method public java.lang.CharSequence getSwitchTextOn();
+    method public void setSwitchTextOff(java.lang.CharSequence);
+    method public void setSwitchTextOff(int);
+    method public void setSwitchTextOn(java.lang.CharSequence);
+    method public void setSwitchTextOn(int);
+  }
+
+}
+
diff --git a/v14/preference/api/current.txt b/v14/preference/api/current.txt
index cbf8fe5..5ebd7cf 100644
--- a/v14/preference/api/current.txt
+++ b/v14/preference/api/current.txt
@@ -3,7 +3,6 @@
   public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
     ctor public EditTextPreferenceDialogFragment();
     method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
-    method protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
     method public void onDialogClosed(boolean);
   }
 
@@ -61,6 +60,8 @@
     method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
     method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
     method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void setDivider(android.graphics.drawable.Drawable);
+    method public void setDividerHeight(int);
     method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
     method public void setPreferencesFromResource(int, java.lang.String);
     field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index 772b353..b5129b1 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -54,3 +54,37 @@
         abortOnError false
     }
 }
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri(rootProject.ext.supportRepoOut)) {
+            }
+
+            pom.project {
+                name 'Android Support Preference v14'
+                description "Android Support Preference v14"
+                url 'http://developer.android.com/tools/extras/support-library.html'
+                inceptionYear '2015'
+
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                        distribution 'repo'
+                    }
+                }
+
+                scm {
+                    url "http://source.android.com"
+                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+                }
+                developers {
+                    developer {
+                        name 'The Android Open Source Project'
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/v14/preference/res/drawable/preference_list_divider_material.xml b/v14/preference/res/drawable/preference_list_divider_material.xml
new file mode 100644
index 0000000..a5913deb
--- /dev/null
+++ b/v14/preference/res/drawable/preference_list_divider_material.xml
@@ -0,0 +1,24 @@
+<?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
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:tint="?android:attr/colorForeground">
+    <solid android:color="#1f000000" />
+    <size
+        android:height="1dp"
+        android:width="1dp" />
+</shape>
diff --git a/v14/preference/res/layout-v17/preference_information_material.xml b/v14/preference/res/layout-v17/preference_information_material.xml
index a376c6a..7b1d823 100644
--- a/v14/preference/res/layout-v17/preference_information_material.xml
+++ b/v14/preference/res/layout-v17/preference_information_material.xml
@@ -48,7 +48,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceListItem" />
+            android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead" />
 
         <TextView android:id="@android:id/summary"
             android:layout_width="wrap_content"
diff --git a/v14/preference/res/layout-v17/preference_material.xml b/v14/preference/res/layout-v17/preference_material.xml
index e624773..bc56718 100644
--- a/v14/preference/res/layout-v17/preference_material.xml
+++ b/v14/preference/res/layout-v17/preference_material.xml
@@ -23,7 +23,7 @@
     android:gravity="center_vertical"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:background="?android:attr/activatedBackgroundIndicator"
+    android:background="?android:attr/selectableItemBackground"
     android:clipToPadding="false"
     android:focusable="true" >
 
@@ -57,7 +57,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
             android:ellipsize="marquee" />
 
         <TextView android:id="@android:id/summary"
diff --git a/v14/preference/res/layout-v21/preference_material.xml b/v14/preference/res/layout-v21/preference_material.xml
index 392a2ea..da6b69f 100644
--- a/v14/preference/res/layout-v21/preference_material.xml
+++ b/v14/preference/res/layout-v21/preference_material.xml
@@ -23,7 +23,7 @@
     android:gravity="center_vertical"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:background="?android:attr/activatedBackgroundIndicator"
+    android:background="?android:attr/selectableItemBackground"
     android:clipToPadding="false"
     android:focusable="true" >
 
diff --git a/v14/preference/res/layout/preference_information_material.xml b/v14/preference/res/layout/preference_information_material.xml
index 54a577c..1090c61 100644
--- a/v14/preference/res/layout/preference_information_material.xml
+++ b/v14/preference/res/layout/preference_information_material.xml
@@ -48,7 +48,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceListItem" />
+            android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead" />
 
         <TextView android:id="@android:id/summary"
             android:layout_width="wrap_content"
diff --git a/v14/preference/res/layout/preference_material.xml b/v14/preference/res/layout/preference_material.xml
index 6135053..e25340e 100644
--- a/v14/preference/res/layout/preference_material.xml
+++ b/v14/preference/res/layout/preference_material.xml
@@ -23,7 +23,7 @@
     android:gravity="center_vertical"
     android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
     android:paddingRight="?android:attr/listPreferredItemPaddingRight"
-    android:background="?android:attr/activatedBackgroundIndicator"
+    android:background="?android:attr/selectableItemBackground"
     android:clipToPadding="false"
     android:focusable="true" >
 
@@ -57,7 +57,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
             android:ellipsize="marquee" />
 
         <TextView android:id="@android:id/summary"
diff --git a/v17/preference-leanback/res/values/ids.xml b/v14/preference/res/values-v17/styles.xml
similarity index 80%
rename from v17/preference-leanback/res/values/ids.xml
rename to v14/preference/res/values-v17/styles.xml
index 20c1eda..e0b478f 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v14/preference/res/values-v17/styles.xml
@@ -16,5 +16,9 @@
   -->
 
 <resources>
-    <item name="transitionPosition" type="id" />
+    <style name="PreferenceFragmentList.Material">
+        <item name="android:paddingStart">0dp</item>
+        <item name="android:paddingEnd">0dp</item>
+    </style>
+
 </resources>
diff --git a/v14/preference/res/values/attrs.xml b/v14/preference/res/values/attrs.xml
index 62d9e47..16f9699 100644
--- a/v14/preference/res/values/attrs.xml
+++ b/v14/preference/res/values/attrs.xml
@@ -1,19 +1,19 @@
 <?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
-  -->
+    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
+    -->
 
 <resources>
     <declare-styleable name="SwitchPreference">
@@ -52,4 +52,15 @@
         <attr name="entryValues" />
         <attr name="android:entryValues" />
     </declare-styleable>
+
+    <!-- Base attributes available to PreferenceFragment. -->
+    <declare-styleable name="PreferenceFragment">
+        <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
+        <attr name="android:layout" />
+        <!-- List separator to draw between preference views -->
+        <attr name="android:divider" />
+        <!-- List separator height -->
+        <attr name="android:dividerHeight" />
+    </declare-styleable>
+
 </resources>
diff --git a/v14/preference/res/values/styles.xml b/v14/preference/res/values/styles.xml
index daf683c..c197121 100644
--- a/v14/preference/res/values/styles.xml
+++ b/v14/preference/res/values/styles.xml
@@ -17,53 +17,70 @@
 
 <resources>
     <style name="Preference.SwitchPreference">
-        <item name="widgetLayout">@layout/preference_widget_switch</item>
-        <item name="switchTextOn">@string/v7_preference_on</item>
-        <item name="switchTextOff">@string/v7_preference_off</item>
+        <item name="android:widgetLayout">@layout/preference_widget_switch</item>
+        <item name="android:switchTextOn">@string/v7_preference_on</item>
+        <item name="android:switchTextOff">@string/v7_preference_off</item>
     </style>
 
     <style name="Preference.Material">
-        <item name="layout">@layout/preference_material</item>
+        <item name="android:layout">@layout/preference_material</item>
     </style>
 
     <style name="Preference.Information.Material">
-        <item name="layout">@layout/preference_information_material</item>
-        <item name="enabled">false</item>
-        <item name="shouldDisableView">false</item>
+        <item name="android:layout">@layout/preference_information_material</item>
+        <item name="android:enabled">false</item>
+        <item name="android:shouldDisableView">false</item>
     </style>
 
     <style name="Preference.Category.Material">
-        <item name="layout">@layout/preference_category_material</item>
+        <item name="android:layout">@layout/preference_category_material</item>
     </style>
 
     <style name="Preference.CheckBoxPreference.Material">
-        <item name="layout">@layout/preference_material</item>
+        <item name="android:layout">@layout/preference_material</item>
     </style>
 
     <style name="Preference.SwitchPreferenceCompat.Material">
-        <item name="layout">@layout/preference_material</item>
+        <item name="android:layout">@layout/preference_material</item>
     </style>
 
     <style name="Preference.SwitchPreference.Material">
-        <item name="layout">@layout/preference_material</item>
+        <item name="android:layout">@layout/preference_material</item>
     </style>
 
     <style name="Preference.PreferenceScreen.Material">
-        <item name="layout">@layout/preference_material</item>
+        <item name="android:layout">@layout/preference_material</item>
     </style>
 
     <style name="Preference.DialogPreference.Material">
-        <item name="layout">@layout/preference_material</item>
+        <item name="android:layout">@layout/preference_material</item>
     </style>
 
     <style name="Preference.DialogPreference.EditTextPreference.Material">
-        <item name="layout">@layout/preference_material</item>
+        <item name="android:layout">@layout/preference_material</item>
     </style>
 
     <style name="Preference_TextAppearanceMaterialBody2">
         <item name="android:textSize">14sp</item>
-        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:fontFamily">sans-serif</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
+    <style name="Preference_TextAppearanceMaterialSubhead">
+        <item name="android:textSize">16sp</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
+    <style name="PreferenceFragment.Material">
+        <item name="android:divider">@drawable/preference_list_divider_material</item>
+    </style>
+
+    <style name="PreferenceFragmentList.Material">
+        <item name="android:paddingLeft">0dp</item>
+        <item name="android:paddingRight">0dp</item>
     </style>
 
 </resources>
diff --git a/v14/preference/res/values/themes.xml b/v14/preference/res/values/themes.xml
index 2bfe623..64bc91e 100644
--- a/v14/preference/res/values/themes.xml
+++ b/v14/preference/res/values/themes.xml
@@ -18,10 +18,13 @@
 <resources>
     <style name="PreferenceThemeOverlay.v14">
         <item name="switchPreferenceStyle">@style/Preference.SwitchPreference</item>
+        <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
     </style>
 
     <style name="PreferenceThemeOverlay.v14.Material">
         <item name="preferenceScreenStyle">@style/Preference.PreferenceScreen.Material</item>
+        <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment.Material</item>
+        <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
         <item name="preferenceCategoryStyle">@style/Preference.Category.Material</item>
         <item name="preferenceStyle">@style/Preference.Material</item>
         <item name="preferenceInformationStyle">@style/Preference.Information.Material</item>
@@ -30,5 +33,6 @@
         <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.Material</item>
         <item name="dialogPreferenceStyle">@style/Preference.DialogPreference.Material</item>
         <item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference.Material</item>
+        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
     </style>
 </resources>
diff --git a/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
index caf08a8..498b874 100644
--- a/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
@@ -19,8 +19,6 @@
 import android.os.Bundle;
 import android.support.v7.preference.EditTextPreference;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.widget.EditText;
 
 public class EditTextPreferenceDialogFragment extends PreferenceDialogFragment {
@@ -40,19 +38,14 @@
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
 
-        mEditText = new EditText(view.getContext());
-        // Give it an ID so it can be saved/restored
-        mEditText.setId(android.R.id.edit);
+        mEditText = (EditText) view.findViewById(android.R.id.edit);
+
+        if (mEditText == null) {
+            throw new IllegalStateException("Dialog view must contain an EditText with id" +
+                    " @android:id/edit");
+        }
 
         mEditText.setText(getEditTextPreference().getText());
-
-        ViewParent oldParent = mEditText.getParent();
-        if (oldParent != view) {
-            if (oldParent != null) {
-                ((ViewGroup) oldParent).removeView(mEditText);
-            }
-            onAddEditTextToDialogView(view, mEditText);
-        }
     }
 
     private EditTextPreference getEditTextPreference() {
@@ -66,20 +59,6 @@
         return true;
     }
 
-    /**
-     * Adds the EditText widget of this preference to the dialog's view.
-     *
-     * @param dialogView The dialog view.
-     */
-    protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
-        ViewGroup container = (ViewGroup) dialogView
-                .findViewById(R.id.edittext_container);
-        if (container != null) {
-            container.addView(editText, ViewGroup.LayoutParams.FILL_PARENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-        }
-    }
-
     @Override
     public void onDialogClosed(boolean positiveResult) {
 
diff --git a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
index 838d32d..b9fc935 100644
--- a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
+++ b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
@@ -20,11 +20,15 @@
 import android.app.Fragment;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.support.annotation.Nullable;
 import android.support.annotation.XmlRes;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.preference.DialogPreference;
 import android.support.v7.preference.EditTextPreference;
 import android.support.v7.preference.ListPreference;
@@ -32,6 +36,7 @@
 import android.support.v7.preference.PreferenceGroupAdapter;
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.PreferenceViewHolder;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.util.TypedValue;
@@ -58,7 +63,7 @@
  * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
  * denote a screen break--that is the preferences contained within subsequent
  * {@link PreferenceScreen} should be shown on another screen. The preference
- * framework handles showing these other screens from the preference hierarchy.
+ * framework handles this by calling {@link #onNavigateToScreen(PreferenceScreen)}.
  * <p>
  * The preference hierarchy can be formed in multiple ways:
  * <li> From an XML file specifying the hierarchy
@@ -130,10 +135,7 @@
 
     private int mLayoutResId = R.layout.preference_list_fragment;
 
-    /**
-     * The starting request code given out to preference framework.
-     */
-    private static final int FIRST_REQUEST_CODE = 100;
+    private final DividerDecoration mDividerDecoration = new DividerDecoration();
 
     private static final int MSG_BIND_PREFERENCES = 1;
     private Handler mHandler = new Handler() {
@@ -239,16 +241,27 @@
             Bundle savedInstanceState) {
 
         TypedArray a = mStyledContext.obtainStyledAttributes(null,
-                R.styleable.PreferenceFragmentCompat,
+                R.styleable.PreferenceFragment,
                 R.attr.preferenceFragmentStyle,
                 0);
 
-        mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
-                mLayoutResId);
+        mLayoutResId = a.getResourceId(R.styleable.PreferenceFragment_android_layout, mLayoutResId);
+
+        final Drawable divider = a.getDrawable(R.styleable.PreferenceFragment_android_divider);
+        final int dividerHeight = a.getInt(R.styleable.PreferenceFragment_android_dividerHeight,
+                -1);
 
         a.recycle();
 
-        final View view = inflater.inflate(mLayoutResId, container, false);
+        // Need to theme the inflater to pick up the preferenceFragmentListStyle
+        final TypedValue tv = new TypedValue();
+        getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
+        final int theme = tv.resourceId;
+
+        final Context themedContext = new ContextThemeWrapper(inflater.getContext(), theme);
+        final LayoutInflater themedInflater = inflater.cloneInContext(themedContext);
+
+        final View view = themedInflater.inflate(mLayoutResId, container, false);
 
         final View rawListContainer = view.findViewById(R.id.list_container);
         if (!(rawListContainer instanceof ViewGroup)) {
@@ -258,18 +271,49 @@
 
         final ViewGroup listContainer = (ViewGroup) rawListContainer;
 
-        final RecyclerView listView = onCreateRecyclerView(inflater, listContainer,
+        final RecyclerView listView = onCreateRecyclerView(themedInflater, listContainer,
                 savedInstanceState);
         if (listView == null) {
             throw new RuntimeException("Could not create RecyclerView");
         }
 
         mList = listView;
+
+        listView.addItemDecoration(mDividerDecoration);
+        setDivider(divider);
+        if (dividerHeight != -1) {
+            setDividerHeight(dividerHeight);
+        }
+
         listContainer.addView(mList);
         mHandler.post(mRequestFocus);
         return view;
     }
 
+    /**
+     * Sets the drawable that will be drawn between each item in the list.
+     * <p>
+     * <strong>Note:</strong> If the drawable does not have an intrinsic
+     * height, you should also call {@link #setDividerHeight(int)}.
+     *
+     * @param divider the drawable to use
+     * @attr ref R.styleable#PreferenceFragment_android_divider
+     */
+    public void setDivider(Drawable divider) {
+        mDividerDecoration.setDivider(divider);
+    }
+
+    /**
+     * Sets the height of the divider that will be drawn between each item in the list. Calling
+     * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
+     *
+     * @param height The new height of the divider in pixels.
+     * @attr ref R.styleable#PreferenceFragment_android_dividerHeight
+     */
+    public void setDividerHeight(int height) {
+        mDividerDecoration.setDividerHeight(height);
+    }
+
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
@@ -583,4 +627,78 @@
     public Fragment getCallbackFragment() {
         return null;
     }
+
+    private class DividerDecoration extends RecyclerView.ItemDecoration {
+
+        private Drawable mDivider;
+        private int mDividerHeight;
+
+        @Override
+        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+            if (mDivider == null) {
+                return;
+            }
+            final int childCount = parent.getChildCount();
+            final int width = parent.getWidth();
+            for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+                final View view = parent.getChildAt(childViewIndex);
+                if (shouldDrawDividerAbove(view, parent)) {
+                    int top = (int) ViewCompat.getY(view);
+                    mDivider.setBounds(0, top, width, top + mDividerHeight);
+                    mDivider.draw(c);
+                }
+                if (shouldDrawDividerBelow(view, parent)) {
+                    int top = (int) ViewCompat.getY(view) + view.getHeight();
+                    mDivider.setBounds(0, top, width, top + mDividerHeight);
+                    mDivider.draw(c);
+                }
+            }
+        }
+
+        @Override
+        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                RecyclerView.State state) {
+            if (shouldDrawDividerAbove(view, parent)) {
+                outRect.top = mDividerHeight;
+            }
+            if (shouldDrawDividerBelow(view, parent)) {
+                outRect.bottom = mDividerHeight;
+            }
+        }
+
+        private boolean shouldDrawDividerAbove(View view, RecyclerView parent) {
+            final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
+            return holder.getAdapterPosition() == 0 &&
+                    ((PreferenceViewHolder) holder).isDividerAllowedAbove();
+        }
+
+        private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
+            final PreferenceViewHolder holder =
+                    (PreferenceViewHolder) parent.getChildViewHolder(view);
+            boolean nextAllowed = true;
+            int index = parent.indexOfChild(view);
+            if (index < parent.getChildCount() - 1) {
+                final View nextView = parent.getChildAt(index + 1);
+                final PreferenceViewHolder nextHolder =
+                        (PreferenceViewHolder) parent.getChildViewHolder(nextView);
+                nextAllowed = nextHolder.isDividerAllowedAbove();
+            }
+            return nextAllowed && holder.isDividerAllowedBelow();
+        }
+
+        public void setDivider(Drawable divider) {
+            if (divider != null) {
+                mDividerHeight = divider.getIntrinsicHeight();
+            } else {
+                mDividerHeight = 0;
+            }
+            mDivider = divider;
+            mList.invalidateItemDecorations();
+        }
+
+        public void setDividerHeight(int dividerHeight) {
+            mDividerHeight = dividerHeight;
+            mList.invalidateItemDecorations();
+        }
+    }
 }
diff --git a/v17/leanback/.classpath b/v17/leanback/.classpath
index 7bc01d9..f568681 100644
--- a/v17/leanback/.classpath
+++ b/v17/leanback/.classpath
@@ -1,9 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="src" path="gen"/>
 	<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
 	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
 	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="api21"/>
+	<classpathentry kind="src" path="api23"/>
+	<classpathentry kind="src" path="jbmr2"/>
+	<classpathentry kind="src" path="common"/>
+	<classpathentry kind="src" path="kitkat"/>
+	<classpathentry kind="src" path="gen"/>
 	<classpathentry kind="output" path="bin/classes"/>
 </classpath>
diff --git a/v17/leanback/Android.mk b/v17/leanback/Android.mk
index dd03d6a..2dc78a7 100644
--- a/v17/leanback/Android.mk
+++ b/v17/leanback/Android.mk
@@ -28,6 +28,8 @@
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files := $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 #  Base sub-library contains classes both needed by api-level specific libraries
@@ -38,6 +40,20 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, common)
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
+# -----------------------------------------------------------------------
+
+#  A helper sub-library that makes direct use of API 23.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v17-leanback-api23
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, api23)
+LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 #  A helper sub-library that makes direct use of API 21.
@@ -48,6 +64,8 @@
 LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 #  A helper sub-library that makes direct use of KitKat APIs.
@@ -58,6 +76,8 @@
 LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 #  A helper sub-library that makes direct use of JBMR2 APIs.
@@ -68,6 +88,8 @@
 LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # Here is the final static library that apps can link against.
@@ -79,6 +101,7 @@
 LOCAL_SDK_VERSION := 17
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v17-leanback-kitkat android-support-v17-leanback-jbmr2 \
+        android-support-v17-leanback-api23 \
         android-support-v17-leanback-api21 android-support-v17-leanback-common
 LOCAL_JAVA_LIBRARIES := \
         android-support-v4 \
@@ -86,6 +109,7 @@
         android-support-v17-leanback-res
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
 
 # ===========================================================
 # Common Droiddoc vars
@@ -131,7 +155,6 @@
 # ---------------------------------------------
 support_module := $(LOCAL_MODULE)
 support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(leanback.docs.src_files)
 support_module_java_libraries := $(leanback.docs.java_libraries)
 support_module_java_packages := android.support.v17.leanback*
 include $(SUPPORT_API_CHECK)
diff --git a/v17/leanback/api/23.txt b/v17/leanback/api/23.0.0.txt
similarity index 100%
rename from v17/leanback/api/23.txt
rename to v17/leanback/api/23.0.0.txt
diff --git a/v17/leanback/api/23.1.0.txt b/v17/leanback/api/23.1.0.txt
new file mode 100644
index 0000000..962367d
--- /dev/null
+++ b/v17/leanback/api/23.1.0.txt
@@ -0,0 +1,1796 @@
+package android.support.v17.leanback.app {
+
+  public final class BackgroundManager {
+    method public void attach(android.view.Window);
+    method public final int getColor();
+    method public android.graphics.drawable.Drawable getDefaultDimLayer();
+    method public android.graphics.drawable.Drawable getDimLayer();
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public static android.support.v17.leanback.app.BackgroundManager getInstance(android.app.Activity);
+    method public boolean isAttached();
+    method public void release();
+    method public void setBitmap(android.graphics.Bitmap);
+    method public void setColor(int);
+    method public void setDimLayer(android.graphics.drawable.Drawable);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setThemeDrawableResourceId(int);
+  }
+
+   abstract class BaseRowFragment extends android.app.Fragment {
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+   abstract class BaseRowSupportFragment extends android.support.v4.app.Fragment {
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+  }
+
+  public class BrowseFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public BrowseFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
+    method public void enableRowScaling(boolean);
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBrandColor();
+    method public int getHeadersState();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public final boolean isHeadersTransitionOnBackEnabled();
+    method public boolean isInHeadersTransition();
+    method public boolean isShowingHeaders();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method public void onSaveInstanceState(android.os.Bundle);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBrandColor(int);
+    method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseFragment.BrowseTransitionListener);
+    method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setHeadersState(int);
+    method public final void setHeadersTransitionOnBackEnabled(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void startHeadersTransition(boolean);
+    field public static final int HEADERS_DISABLED = 3; // 0x3
+    field public static final int HEADERS_ENABLED = 1; // 0x1
+    field public static final int HEADERS_HIDDEN = 2; // 0x2
+  }
+
+  public static class BrowseFragment.BrowseTransitionListener {
+    ctor public BrowseFragment.BrowseTransitionListener();
+    method public void onHeadersTransitionStart(boolean);
+    method public void onHeadersTransitionStop(boolean);
+  }
+
+  public class BrowseSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public BrowseSupportFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
+    method public void enableRowScaling(boolean);
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBrandColor();
+    method public int getHeadersState();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public final boolean isHeadersTransitionOnBackEnabled();
+    method public boolean isInHeadersTransition();
+    method public boolean isShowingHeaders();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method public void onSaveInstanceState(android.os.Bundle);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBrandColor(int);
+    method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseSupportFragment.BrowseTransitionListener);
+    method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public void setHeadersState(int);
+    method public final void setHeadersTransitionOnBackEnabled(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void startHeadersTransition(boolean);
+    field public static final int HEADERS_DISABLED = 3; // 0x3
+    field public static final int HEADERS_ENABLED = 1; // 0x1
+    field public static final int HEADERS_HIDDEN = 2; // 0x2
+  }
+
+  public static class BrowseSupportFragment.BrowseTransitionListener {
+    ctor public BrowseSupportFragment.BrowseTransitionListener();
+    method public void onHeadersTransitionStart(boolean);
+    method public void onHeadersTransitionStop(boolean);
+  }
+
+  public class DetailsFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public DetailsFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+    method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+    method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+  }
+
+  public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public DetailsSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+    method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+    method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+  }
+
+  public class ErrorFragment extends android.app.Fragment {
+    ctor public ErrorFragment();
+    method public android.graphics.drawable.Drawable getBackgroundDrawable();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.view.View.OnClickListener getButtonClickListener();
+    method public java.lang.String getButtonText();
+    method public android.graphics.drawable.Drawable getImageDrawable();
+    method public java.lang.CharSequence getMessage();
+    method public java.lang.String getTitle();
+    method public boolean isBackgroundTranslucent();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonClickListener(android.view.View.OnClickListener);
+    method public void setButtonText(java.lang.String);
+    method public void setDefaultBackground(boolean);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setMessage(java.lang.CharSequence);
+    method public void setTitle(java.lang.String);
+  }
+
+  public class ErrorSupportFragment extends android.support.v4.app.Fragment {
+    ctor public ErrorSupportFragment();
+    method public android.graphics.drawable.Drawable getBackgroundDrawable();
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.view.View.OnClickListener getButtonClickListener();
+    method public java.lang.String getButtonText();
+    method public android.graphics.drawable.Drawable getImageDrawable();
+    method public java.lang.CharSequence getMessage();
+    method public java.lang.String getTitle();
+    method public boolean isBackgroundTranslucent();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonClickListener(android.view.View.OnClickListener);
+    method public void setButtonText(java.lang.String);
+    method public void setDefaultBackground(boolean);
+    method public void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setMessage(java.lang.CharSequence);
+    method public void setTitle(java.lang.String);
+  }
+
+  public class GuidedStepFragment extends android.app.Fragment {
+    ctor public GuidedStepFragment();
+    method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment);
+    method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public static int addAsRoot(android.app.Activity, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public android.view.View getActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method protected int getContainerIdForBackground();
+    method public static android.support.v17.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
+    method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public int getSelectedActionPosition();
+    method public int getUiStyle();
+    method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+    method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected android.app.Fragment onProvideBackgroundFragment();
+    method protected void onProvideFragmentTransitions();
+    method public int onProvideTheme();
+    method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setSelectedActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final int UI_STYLE_DEFAULT = 0; // 0x0
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+  }
+
+  public static class GuidedStepFragment.GuidedStepBackgroundFragment extends android.app.Fragment {
+    ctor public GuidedStepFragment.GuidedStepBackgroundFragment();
+    method protected void onProvideFragmentTransitions();
+  }
+
+  public class GuidedStepSupportFragment extends android.support.v4.app.Fragment {
+    ctor public GuidedStepSupportFragment();
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment);
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public static int addAsRoot(android.support.v4.app.FragmentActivity, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public android.view.View getActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method protected int getContainerIdForBackground();
+    method public static android.support.v17.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(android.support.v4.app.FragmentManager);
+    method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public int getSelectedActionPosition();
+    method public int getUiStyle();
+    method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+    method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected android.support.v4.app.Fragment onProvideBackgroundSupportFragment();
+    method protected void onProvideFragmentTransitions();
+    method public int onProvideTheme();
+    method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setSelectedActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final int UI_STYLE_DEFAULT = 0; // 0x0
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+  }
+
+  public static class GuidedStepSupportFragment.GuidedStepBackgroundSupportFragment extends android.support.v4.app.Fragment {
+    ctor public GuidedStepSupportFragment.GuidedStepBackgroundSupportFragment();
+    method protected void onProvideFragmentTransitions();
+  }
+
+  public class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
+    ctor public HeadersFragment();
+    method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener);
+    method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener);
+  }
+
+   static abstract interface HeadersFragment.OnHeaderClickedListener {
+    method public abstract void onHeaderClicked();
+  }
+
+   static abstract interface HeadersFragment.OnHeaderViewSelectedListener {
+    method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public class HeadersSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment {
+    ctor public HeadersSupportFragment();
+    method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener);
+    method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener);
+  }
+
+   static abstract interface HeadersSupportFragment.OnHeaderClickedListener {
+    method public abstract void onHeaderClicked();
+  }
+
+   static abstract interface HeadersSupportFragment.OnHeaderViewSelectedListener {
+    method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public abstract class MediaControllerGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
+    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
+    method public void detach();
+    method public int getCurrentPosition();
+    method public int getCurrentSpeedId();
+    method public android.graphics.drawable.Drawable getMediaArt();
+    method public final android.support.v4.media.session.MediaControllerCompat getMediaController();
+    method public int getMediaDuration();
+    method public java.lang.CharSequence getMediaSubtitle();
+    method public java.lang.CharSequence getMediaTitle();
+    method public long getSupportedActions();
+    method public boolean hasValidMedia();
+    method public boolean isMediaPlaying();
+    method protected void pausePlayback();
+    method protected void skipToNext();
+    method protected void skipToPrevious();
+    method protected void startPlayback(int);
+  }
+
+  public abstract class PlaybackControlGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+    ctor public PlaybackControlGlue(android.content.Context, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
+    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+    method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    method public void enableProgressUpdating(boolean);
+    method public android.content.Context getContext();
+    method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+    method public abstract int getCurrentPosition();
+    method public abstract int getCurrentSpeedId();
+    method public int[] getFastForwardSpeeds();
+    method public android.support.v17.leanback.app.PlaybackOverlayFragment getFragment();
+    method public abstract android.graphics.drawable.Drawable getMediaArt();
+    method public abstract int getMediaDuration();
+    method public abstract java.lang.CharSequence getMediaSubtitle();
+    method public abstract java.lang.CharSequence getMediaTitle();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public int[] getRewindSpeeds();
+    method public abstract long getSupportedActions();
+    method public int getUpdatePeriod();
+    method public abstract boolean hasValidMedia();
+    method public boolean isFadingEnabled();
+    method public abstract boolean isMediaPlaying();
+    method public void onActionClicked(android.support.v17.leanback.widget.Action);
+    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+    method protected void onMetadataChanged();
+    method protected abstract void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method protected void onStateChanged();
+    method protected abstract void pausePlayback();
+    method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method public void setFadingEnabled(boolean);
+    method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method protected abstract void skipToNext();
+    method protected abstract void skipToPrevious();
+    method protected abstract void startPlayback(int);
+    method public void updateProgress();
+    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+    field public static final int ACTION_REWIND = 32; // 0x20
+    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+  }
+
+  public abstract class PlaybackControlSupportGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[], int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[], int[]);
+    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+    method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    method public void enableProgressUpdating(boolean);
+    method public android.content.Context getContext();
+    method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+    method public abstract int getCurrentPosition();
+    method public abstract int getCurrentSpeedId();
+    method public int[] getFastForwardSpeeds();
+    method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment getFragment();
+    method public abstract android.graphics.drawable.Drawable getMediaArt();
+    method public abstract int getMediaDuration();
+    method public abstract java.lang.CharSequence getMediaSubtitle();
+    method public abstract java.lang.CharSequence getMediaTitle();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public int[] getRewindSpeeds();
+    method public abstract long getSupportedActions();
+    method public int getUpdatePeriod();
+    method public abstract boolean hasValidMedia();
+    method public boolean isFadingEnabled();
+    method public abstract boolean isMediaPlaying();
+    method public void onActionClicked(android.support.v17.leanback.widget.Action);
+    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+    method protected void onMetadataChanged();
+    method protected abstract void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method protected void onStateChanged();
+    method protected abstract void pausePlayback();
+    method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method public void setFadingEnabled(boolean);
+    method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method protected abstract void skipToNext();
+    method protected abstract void skipToPrevious();
+    method protected abstract void startPlayback(int);
+    method public void updateProgress();
+    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+    field public static final int ACTION_REWIND = 32; // 0x20
+    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+  }
+
+  public class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
+    ctor public PlaybackOverlayFragment();
+    method public int getBackgroundType();
+    method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public final android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
+    method public boolean isFadingEnabled();
+    method public void onDestroyView();
+    method public void onResume();
+    method public void setBackgroundType(int);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public final void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static abstract interface PlaybackOverlayFragment.InputEventHandler {
+    method public abstract boolean handleInputEvent(android.view.InputEvent);
+  }
+
+  public static class PlaybackOverlayFragment.OnFadeCompleteListener {
+    ctor public PlaybackOverlayFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public class PlaybackOverlaySupportFragment extends android.support.v17.leanback.app.DetailsSupportFragment {
+    ctor public PlaybackOverlaySupportFragment();
+    method public int getBackgroundType();
+    method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public final android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
+    method public boolean isFadingEnabled();
+    method public void onDestroyView();
+    method public void onResume();
+    method public void setBackgroundType(int);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public final void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static abstract interface PlaybackOverlaySupportFragment.InputEventHandler {
+    method public abstract boolean handleInputEvent(android.view.InputEvent);
+  }
+
+  public static class PlaybackOverlaySupportFragment.OnFadeCompleteListener {
+    ctor public PlaybackOverlaySupportFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public class RowsFragment extends android.support.v17.leanback.app.BaseRowFragment {
+    ctor public RowsFragment();
+    method public void enableRowScaling(boolean);
+    method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public void setExpand(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+  }
+
+  public class RowsSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment {
+    ctor public RowsSupportFragment();
+    method public void enableRowScaling(boolean);
+    method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public void setExpand(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+  }
+
+  public class SearchFragment extends android.app.Fragment {
+    ctor public SearchFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.content.Intent getRecognizerIntent();
+    method public java.lang.String getTitle();
+    method public static android.support.v17.leanback.app.SearchFragment newInstance(java.lang.String);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchQuery(java.lang.String, boolean);
+    method public void setSearchQuery(android.content.Intent, boolean);
+    method public void setSearchResultProvider(android.support.v17.leanback.app.SearchFragment.SearchResultProvider);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+  }
+
+  public static abstract interface SearchFragment.SearchResultProvider {
+    method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class SearchSupportFragment extends android.support.v4.app.Fragment {
+    ctor public SearchSupportFragment();
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.content.Intent getRecognizerIntent();
+    method public java.lang.String getTitle();
+    method public static android.support.v17.leanback.app.SearchSupportFragment newInstance(java.lang.String);
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchQuery(java.lang.String, boolean);
+    method public void setSearchQuery(android.content.Intent, boolean);
+    method public void setSearchResultProvider(android.support.v17.leanback.app.SearchSupportFragment.SearchResultProvider);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+  }
+
+  public static abstract interface SearchSupportFragment.SearchResultProvider {
+    method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class VerticalGridFragment extends android.support.v17.leanback.app.BrandedFragment {
+    ctor public VerticalGridFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public void onDestroyView();
+    method public void onStart();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+  }
+
+  public class VerticalGridSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+    ctor public VerticalGridSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public void onDestroyView();
+    method public void onStart();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
+    method protected void runEntranceTransition(java.lang.Object);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSelectedPosition(int);
+  }
+
+}
+
+package android.support.v17.leanback.database {
+
+  public abstract class CursorMapper {
+    ctor public CursorMapper();
+    method protected abstract java.lang.Object bind(android.database.Cursor);
+    method protected abstract void bindColumns(android.database.Cursor);
+    method public java.lang.Object convert(android.database.Cursor);
+  }
+
+}
+
+package android.support.v17.leanback.graphics {
+
+  public final class ColorFilterCache {
+    method public static android.support.v17.leanback.graphics.ColorFilterCache getColorFilterCache(int);
+    method public android.graphics.ColorFilter getFilterForLevel(float);
+  }
+
+  public final class ColorFilterDimmer {
+    method public void applyFilterToView(android.view.View);
+    method public static android.support.v17.leanback.graphics.ColorFilterDimmer create(android.support.v17.leanback.graphics.ColorFilterCache, float, float);
+    method public static android.support.v17.leanback.graphics.ColorFilterDimmer createDefault(android.content.Context);
+    method public android.graphics.ColorFilter getColorFilter();
+    method public android.graphics.Paint getPaint();
+    method public void setActiveLevel(float);
+  }
+
+  public final class ColorOverlayDimmer {
+    method public int applyToColor(int);
+    method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createColorOverlayDimmer(int, float, float);
+    method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createDefault(android.content.Context);
+    method public void drawColorOverlay(android.graphics.Canvas, android.view.View, boolean);
+    method public int getAlpha();
+    method public float getAlphaFloat();
+    method public android.graphics.Paint getPaint();
+    method public boolean needsDraw();
+    method public void setActiveLevel(float);
+  }
+
+}
+
+package android.support.v17.leanback.system {
+
+  public class Settings {
+    method public boolean getBoolean(java.lang.String);
+    method public static android.support.v17.leanback.system.Settings getInstance(android.content.Context);
+    method public void setBoolean(java.lang.String, boolean);
+    field public static final java.lang.String PREFER_STATIC_SHADOWS = "PREFER_STATIC_SHADOWS";
+  }
+
+}
+
+package android.support.v17.leanback.widget {
+
+  public abstract class AbstractDetailsDescriptionPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public AbstractDetailsDescriptionPresenter();
+    method protected abstract void onBindDescription(android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, java.lang.Object);
+    method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+  }
+
+  public static class AbstractDetailsDescriptionPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getBody();
+    method public android.widget.TextView getSubtitle();
+    method public android.widget.TextView getTitle();
+  }
+
+  public class Action {
+    ctor public Action(long);
+    ctor public Action(long, java.lang.CharSequence);
+    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence);
+    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence, android.graphics.drawable.Drawable);
+    method public final void addKeyCode(int);
+    method public final android.graphics.drawable.Drawable getIcon();
+    method public final long getId();
+    method public final java.lang.CharSequence getLabel1();
+    method public final java.lang.CharSequence getLabel2();
+    method public final void removeKeyCode(int);
+    method public final boolean respondsToKeyCode(int);
+    method public final void setIcon(android.graphics.drawable.Drawable);
+    method public final void setId(long);
+    method public final void setLabel1(java.lang.CharSequence);
+    method public final void setLabel2(java.lang.CharSequence);
+  }
+
+  public class ArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public ArrayObjectAdapter();
+    method public void add(java.lang.Object);
+    method public void add(int, java.lang.Object);
+    method public void addAll(int, java.util.Collection);
+    method public void clear();
+    method public java.lang.Object get(int);
+    method public int indexOf(java.lang.Object);
+    method public void notifyArrayItemRangeChanged(int, int);
+    method public boolean remove(java.lang.Object);
+    method public int removeItems(int, int);
+    method public void replace(int, java.lang.Object);
+    method public int size();
+    method public java.util.List<E> unmodifiableList();
+  }
+
+  public class BaseCardView extends android.widget.FrameLayout {
+    ctor public BaseCardView(android.content.Context);
+    ctor public BaseCardView(android.content.Context, android.util.AttributeSet);
+    ctor public BaseCardView(android.content.Context, android.util.AttributeSet, int);
+    method public int getCardType();
+    method public int getExtraVisibility();
+    method public int getInfoVisibility();
+    method public boolean isSelectedAnimationDelayed();
+    method public void setCardType(int);
+    method public void setExtraVisibility(int);
+    method public void setInfoVisibility(int);
+    method public void setSelectedAnimationDelayed(boolean);
+    field public static final int CARD_REGION_VISIBLE_ACTIVATED = 1; // 0x1
+    field public static final int CARD_REGION_VISIBLE_ALWAYS = 0; // 0x0
+    field public static final int CARD_REGION_VISIBLE_SELECTED = 2; // 0x2
+    field public static final int CARD_TYPE_INFO_OVER = 1; // 0x1
+    field public static final int CARD_TYPE_INFO_UNDER = 2; // 0x2
+    field public static final int CARD_TYPE_INFO_UNDER_WITH_EXTRA = 3; // 0x3
+    field public static final int CARD_TYPE_MAIN_ONLY = 0; // 0x0
+  }
+
+  public static class BaseCardView.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+    ctor public BaseCardView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public BaseCardView.LayoutParams(int, int);
+    ctor public BaseCardView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public BaseCardView.LayoutParams(android.support.v17.leanback.widget.BaseCardView.LayoutParams);
+    field public static final int VIEW_TYPE_EXTRA = 2; // 0x2
+    field public static final int VIEW_TYPE_INFO = 1; // 0x1
+    field public static final int VIEW_TYPE_MAIN = 0; // 0x0
+    field public int viewType;
+  }
+
+  public class BrowseFrameLayout extends android.widget.FrameLayout {
+    ctor public BrowseFrameLayout(android.content.Context);
+    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet);
+    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener getOnChildFocusListener();
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+    method public void setOnChildFocusListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener);
+    method public void setOnFocusSearchListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener);
+  }
+
+  public static abstract interface BrowseFrameLayout.OnChildFocusListener {
+    method public abstract void onRequestChildFocus(android.view.View, android.view.View);
+    method public abstract boolean onRequestFocusInDescendants(int, android.graphics.Rect);
+  }
+
+  public static abstract interface BrowseFrameLayout.OnFocusSearchListener {
+    method public abstract android.view.View onFocusSearch(android.view.View, int);
+  }
+
+  public final class ClassPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public ClassPresenterSelector();
+    method public void addClassPresenter(java.lang.Class<?>, android.support.v17.leanback.widget.Presenter);
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+  }
+
+  public class ControlButtonPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public ControlButtonPresenterSelector();
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter getPrimaryPresenter();
+    method public android.support.v17.leanback.widget.Presenter getSecondaryPresenter();
+  }
+
+  public class CursorObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public CursorObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public CursorObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public CursorObjectAdapter();
+    method public void changeCursor(android.database.Cursor);
+    method public void close();
+    method public java.lang.Object get(int);
+    method public final android.database.Cursor getCursor();
+    method public final android.support.v17.leanback.database.CursorMapper getMapper();
+    method protected final void invalidateCache(int);
+    method protected final void invalidateCache(int, int);
+    method public boolean isClosed();
+    method protected void onCursorChanged();
+    method protected void onMapperChanged();
+    method public final void setMapper(android.support.v17.leanback.database.CursorMapper);
+    method public int size();
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+  }
+
+  public class DetailsOverviewLogoPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public DetailsOverviewLogoPresenter();
+    method public boolean isBoundToImage(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setContext(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+  }
+
+  public static class DetailsOverviewLogoPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
+    field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter mParentPresenter;
+    field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder mParentViewHolder;
+  }
+
+  public class DetailsOverviewRow extends android.support.v17.leanback.widget.Row {
+    ctor public DetailsOverviewRow(java.lang.Object);
+    method public final deprecated void addAction(android.support.v17.leanback.widget.Action);
+    method public final deprecated void addAction(int, android.support.v17.leanback.widget.Action);
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+    method public final deprecated java.util.List<android.support.v17.leanback.widget.Action> getActions();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getActionsAdapter();
+    method public final android.graphics.drawable.Drawable getImageDrawable();
+    method public final java.lang.Object getItem();
+    method public boolean isImageScaleUpAllowed();
+    method public final deprecated boolean removeAction(android.support.v17.leanback.widget.Action);
+    method public final void setActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+    method public final void setImageDrawable(android.graphics.drawable.Drawable);
+    method public void setImageScaleUpAllowed(boolean);
+    method public final void setItem(java.lang.Object);
+  }
+
+  public static class DetailsOverviewRow.Listener {
+    ctor public DetailsOverviewRow.Listener();
+    method public void onActionsAdapterChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onImageDrawableChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+    method public void onItemChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+  }
+
+  public deprecated class DetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public DetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public int getBackgroundColor();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public boolean isStyleLarge();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public void setBackgroundColor(int);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+    method public void setStyleLarge(boolean);
+  }
+
+  public final class DetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public DetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter);
+    field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDetailsDescriptionViewHolder;
+  }
+
+  public abstract interface FacetProvider {
+    method public abstract java.lang.Object getFacet(java.lang.Class<?>);
+  }
+
+  public abstract interface FacetProviderAdapter {
+    method public abstract android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+  }
+
+  public abstract interface FocusHighlight {
+    field public static final int ZOOM_FACTOR_LARGE = 3; // 0x3
+    field public static final int ZOOM_FACTOR_MEDIUM = 2; // 0x2
+    field public static final int ZOOM_FACTOR_NONE = 0; // 0x0
+    field public static final int ZOOM_FACTOR_SMALL = 1; // 0x1
+    field public static final int ZOOM_FACTOR_XSMALL = 4; // 0x4
+  }
+
+  public class FocusHighlightHelper {
+    ctor public FocusHighlightHelper();
+    method public static void setupBrowseItemFocusHighlight(android.support.v17.leanback.widget.ItemBridgeAdapter, int, boolean);
+    method public static void setupHeaderItemFocusHighlight(android.support.v17.leanback.widget.VerticalGridView);
+  }
+
+  public abstract interface FragmentAnimationProvider {
+    method public abstract void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public abstract void onImeDisappearing(java.util.List<android.animation.Animator>);
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+    ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public final int getActionsBackgroundColor();
+    method public final int getAlignmentMode();
+    method public final int getBackgroundColor();
+    method public final int getInitialState();
+    method protected int getLayoutResourceId();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public final boolean isParticipatingEntranceTransition();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public final void notifyOnBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+    method protected void onLayoutLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+    method protected void onLayoutOverviewFrame(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+    method protected void onStateChanged(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+    method public final void setActionsBackgroundColor(int);
+    method public final void setAlignmentMode(int);
+    method public final void setBackgroundColor(int);
+    method public final void setInitialState(int);
+    method public final void setListener(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public final void setParticipatingEntranceTransition(boolean);
+    method public final void setState(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+    field public static final int ALIGN_MODE_MIDDLE = 1; // 0x1
+    field public static final int ALIGN_MODE_START = 0; // 0x0
+    field public static final int STATE_FULL = 1; // 0x1
+    field public static final int STATE_HALF = 0; // 0x0
+    field public static final int STATE_SMALL = 2; // 0x2
+    field protected int mInitialState;
+  }
+
+  public static abstract class FullWidthDetailsOverviewRowPresenter.Listener {
+    ctor public FullWidthDetailsOverviewRowPresenter.Listener();
+    method public void onBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+    method protected android.support.v17.leanback.widget.DetailsOverviewRow.Listener createRowListener();
+    method public final android.view.ViewGroup getActionsRow();
+    method public final android.view.ViewGroup getDetailsDescriptionFrame();
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder getDetailsDescriptionViewHolder();
+    method public final android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder getLogoViewHolder();
+    method public final android.view.ViewGroup getOverviewView();
+    method public final int getState();
+    field protected final android.support.v17.leanback.widget.DetailsOverviewRow.Listener mRowListener;
+  }
+
+  public class FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener extends android.support.v17.leanback.widget.DetailsOverviewRow.Listener {
+    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener();
+  }
+
+  public class FullWidthDetailsOverviewSharedElementHelper extends android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener {
+    ctor public FullWidthDetailsOverviewSharedElementHelper();
+    method public boolean getAutoStartSharedElementTransition();
+    method public void setAutoStartSharedElementTransition(boolean);
+    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+    method public void startPostponedEnterTransition();
+  }
+
+  public class GuidanceStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+    ctor public GuidanceStylist();
+    method public android.widget.TextView getBreadcrumbView();
+    method public android.widget.TextView getDescriptionView();
+    method public android.widget.ImageView getIconView();
+    method public android.widget.TextView getTitleView();
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.support.v17.leanback.widget.GuidanceStylist.Guidance);
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+    method public int onProvideLayoutId();
+  }
+
+  public static class GuidanceStylist.Guidance {
+    ctor public GuidanceStylist.Guidance(java.lang.String, java.lang.String, java.lang.String, android.graphics.drawable.Drawable);
+    method public java.lang.String getBreadcrumb();
+    method public java.lang.String getDescription();
+    method public android.graphics.drawable.Drawable getIconDrawable();
+    method public java.lang.String getTitle();
+  }
+
+  public class GuidedAction extends android.support.v17.leanback.widget.Action {
+    method public int getCheckSetId();
+    method public java.lang.CharSequence getDescription();
+    method public java.lang.CharSequence getEditTitle();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getTitle();
+    method public boolean hasMultilineDescription();
+    method public boolean hasNext();
+    method public boolean infoOnly();
+    method public boolean isChecked();
+    method public boolean isEditTitleUsed();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public void setChecked(boolean);
+    method public void setDescription(java.lang.CharSequence);
+    method public void setEditTitle(java.lang.CharSequence);
+    method public void setEnabled(boolean);
+    method public void setTitle(java.lang.CharSequence);
+    field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
+    field public static final int NO_CHECK_SET = 0; // 0x0
+    field public static final int NO_DRAWABLE = 0; // 0x0
+  }
+
+  public static class GuidedAction.Builder {
+    ctor public GuidedAction.Builder();
+    method public android.support.v17.leanback.widget.GuidedAction build();
+    method public android.support.v17.leanback.widget.GuidedAction.Builder checkSetId(int);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder checked(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder description(java.lang.String);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder editTitle(java.lang.String);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder editable(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder enabled(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder hasNext(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder icon(android.graphics.drawable.Drawable);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder iconResourceId(int, android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder id(long);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder infoOnly(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder intent(android.content.Intent);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder multilineDescription(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder title(java.lang.String);
+  }
+
+  public class GuidedActionEditText extends android.widget.EditText implements android.support.v17.leanback.widget.ImeKeyMonitor {
+    ctor public GuidedActionEditText(android.content.Context);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet, int);
+    method public void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+  }
+
+  public class GuidedActionsStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+    ctor public GuidedActionsStylist();
+    method public android.support.v17.leanback.widget.VerticalGridView getActionsGridView();
+    method public void onAnimateItemChecked(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemFocused(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemPressed(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+    method public int onProvideItemLayoutId();
+    method public int onProvideLayoutId();
+    field protected android.support.v17.leanback.widget.VerticalGridView mActionsGridView;
+    field protected android.view.View mMainView;
+    field protected android.view.View mSelectorView;
+  }
+
+  public static class GuidedActionsStylist.ViewHolder {
+    ctor public GuidedActionsStylist.ViewHolder(android.view.View);
+    method public android.widget.ImageView getCheckmarkView();
+    method public android.widget.ImageView getChevronView();
+    method public android.view.View getContentView();
+    method public android.widget.TextView getDescriptionView();
+    method public android.widget.EditText getEditableTitleView();
+    method public android.widget.ImageView getIconView();
+    method public android.widget.TextView getTitleView();
+    field public final android.view.View view;
+  }
+
+  public class HeaderItem {
+    ctor public HeaderItem(long, java.lang.String);
+    ctor public HeaderItem(java.lang.String);
+    method public final long getId();
+    method public final java.lang.String getName();
+  }
+
+  public class HorizontalGridView extends android.support.v7.widget.RecyclerView {
+    ctor public HorizontalGridView(android.content.Context);
+    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet);
+    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet, int);
+    method public final boolean getFadingLeftEdge();
+    method public final int getFadingLeftEdgeLength();
+    method public final int getFadingLeftEdgeOffset();
+    method public final boolean getFadingRightEdge();
+    method public final int getFadingRightEdgeLength();
+    method public final int getFadingRightEdgeOffset();
+    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+    method public final void setFadingLeftEdge(boolean);
+    method public final void setFadingLeftEdgeLength(int);
+    method public final void setFadingLeftEdgeOffset(int);
+    method public final void setFadingRightEdge(boolean);
+    method public final void setFadingRightEdgeLength(int);
+    method public final void setFadingRightEdgeOffset(int);
+    method public void setNumRows(int);
+    method public void setRowHeight(int);
+  }
+
+  public final class HorizontalHoverCardSwitcher extends android.support.v17.leanback.widget.PresenterSwitcher {
+    ctor public HorizontalHoverCardSwitcher();
+    method protected void insertView(android.view.View);
+    method public void select(android.support.v17.leanback.widget.HorizontalGridView, android.view.View, java.lang.Object);
+  }
+
+  public class ImageCardView extends android.support.v17.leanback.widget.BaseCardView {
+    ctor public ImageCardView(android.content.Context, int);
+    ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
+    ctor public ImageCardView(android.content.Context);
+    ctor public ImageCardView(android.content.Context, android.util.AttributeSet);
+    method public android.graphics.drawable.Drawable getBadgeImage();
+    method public java.lang.CharSequence getContentText();
+    method public android.graphics.drawable.Drawable getInfoAreaBackground();
+    method public android.graphics.drawable.Drawable getMainImage();
+    method public final android.widget.ImageView getMainImageView();
+    method public java.lang.CharSequence getTitleText();
+    method public void setBadgeImage(android.graphics.drawable.Drawable);
+    method public void setContentText(java.lang.CharSequence);
+    method public void setInfoAreaBackground(android.graphics.drawable.Drawable);
+    method public void setInfoAreaBackgroundColor(int);
+    method public void setMainImage(android.graphics.drawable.Drawable);
+    method public void setMainImage(android.graphics.drawable.Drawable, boolean);
+    method public void setMainImageAdjustViewBounds(boolean);
+    method public void setMainImageDimensions(int, int);
+    method public void setMainImageScaleType(android.widget.ImageView.ScaleType);
+    method public void setTitleText(java.lang.CharSequence);
+    field public static final int CARD_TYPE_FLAG_CONTENT = 2; // 0x2
+    field public static final int CARD_TYPE_FLAG_ICON_LEFT = 8; // 0x8
+    field public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4; // 0x4
+    field public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0; // 0x0
+    field public static final int CARD_TYPE_FLAG_TITLE = 1; // 0x1
+  }
+
+  public abstract interface ImeKeyMonitor {
+    method public abstract void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+  }
+
+  public static abstract interface ImeKeyMonitor.ImeKeyListener {
+    method public abstract boolean onKeyPreIme(android.widget.EditText, int, android.view.KeyEvent);
+  }
+
+  public final class ItemAlignmentFacet {
+    ctor public ItemAlignmentFacet();
+    method public android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[] getAlignmentDefs();
+    method public boolean isMultiAlignment();
+    method public void setAlignmentDefs(android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[]);
+    field public static final float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1.0f;
+  }
+
+  public static class ItemAlignmentFacet.ItemAlignmentDef {
+    ctor public ItemAlignmentFacet.ItemAlignmentDef();
+    method public final int getItemAlignmentFocusViewId();
+    method public final int getItemAlignmentOffset();
+    method public final float getItemAlignmentOffsetPercent();
+    method public final int getItemAlignmentViewId();
+    method public final boolean isItemAlignmentOffsetWithPadding();
+    method public final void setItemAlignmentFocusViewId(int);
+    method public final void setItemAlignmentOffset(int);
+    method public final void setItemAlignmentOffsetPercent(float);
+    method public final void setItemAlignmentOffsetWithPadding(boolean);
+    method public final void setItemAlignmentViewId(int);
+  }
+
+  public class ItemBridgeAdapter extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.leanback.widget.FacetProviderAdapter {
+    ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter, android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ItemBridgeAdapter();
+    method public void clear();
+    method public android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+    method public int getItemCount();
+    method public java.util.ArrayList<android.support.v17.leanback.widget.Presenter> getPresenterMapper();
+    method public android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper getWrapper();
+    method protected void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+    method protected void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method protected void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final void onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    method protected void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final android.support.v7.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method protected void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method protected void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public final void onViewAttachedToWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void onViewDetachedFromWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setAdapterListener(android.support.v17.leanback.widget.ItemBridgeAdapter.AdapterListener);
+    method public void setPresenterMapper(java.util.ArrayList<android.support.v17.leanback.widget.Presenter>);
+    method public void setWrapper(android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper);
+  }
+
+  public static class ItemBridgeAdapter.AdapterListener {
+    ctor public ItemBridgeAdapter.AdapterListener();
+    method public void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+    method public void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+    method public void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+  }
+
+  public class ItemBridgeAdapter.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    method public final java.lang.Object getExtraObject();
+    method public java.lang.Object getFacet(java.lang.Class<?>);
+    method public final java.lang.Object getItem();
+    method public final android.support.v17.leanback.widget.Presenter getPresenter();
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder getViewHolder();
+    method public void setExtraObject(java.lang.Object);
+  }
+
+  public static abstract class ItemBridgeAdapter.Wrapper {
+    ctor public ItemBridgeAdapter.Wrapper();
+    method public abstract android.view.View createWrapper(android.view.View);
+    method public abstract void wrap(android.view.View, android.view.View);
+  }
+
+  public class ItemBridgeAdapterShadowOverlayWrapper extends android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper {
+    ctor public ItemBridgeAdapterShadowOverlayWrapper(android.support.v17.leanback.widget.ShadowOverlayHelper);
+    method public android.view.View createWrapper(android.view.View);
+    method public void wrap(android.view.View, android.view.View);
+  }
+
+  public class ListRow extends android.support.v17.leanback.widget.Row {
+    ctor public ListRow(android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ListRow(long, android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+    ctor public ListRow(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+  }
+
+  public final class ListRowHoverCardView extends android.widget.LinearLayout {
+    ctor public ListRowHoverCardView(android.content.Context);
+    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet);
+    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet, int);
+    method public final java.lang.CharSequence getDescription();
+    method public final java.lang.CharSequence getTitle();
+    method public final void setDescription(java.lang.CharSequence);
+    method public final void setTitle(java.lang.CharSequence);
+  }
+
+  public class ListRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public ListRowPresenter();
+    ctor public ListRowPresenter(int);
+    ctor public ListRowPresenter(int, boolean);
+    method public final boolean areChildRoundedCornersEnabled();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+    method public final void enableChildRoundedCorners(boolean);
+    method public int getExpandedRowHeight();
+    method public final int getFocusZoomFactor();
+    method public final android.support.v17.leanback.widget.PresenterSelector getHoverCardPresenterSelector();
+    method public int getRecycledPoolSize(android.support.v17.leanback.widget.Presenter);
+    method public int getRowHeight();
+    method public final boolean getShadowEnabled();
+    method public final deprecated int getZoomFactor();
+    method public final boolean isFocusDimmerUsed();
+    method public final boolean isKeepChildForeground();
+    method public boolean isUsingDefaultListSelectEffect();
+    method public final boolean isUsingDefaultSelectEffect();
+    method public boolean isUsingDefaultShadow();
+    method public boolean isUsingZOrder(android.content.Context);
+    method public void setExpandedRowHeight(int);
+    method public final void setHoverCardPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public final void setKeepChildForeground(boolean);
+    method public void setRecycledPoolSize(android.support.v17.leanback.widget.Presenter, int);
+    method public void setRowHeight(int);
+    method public final void setShadowEnabled(boolean);
+  }
+
+  public static class ListRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public ListRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.HorizontalGridView, android.support.v17.leanback.widget.ListRowPresenter);
+    method public final android.support.v17.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
+    method public final android.support.v17.leanback.widget.HorizontalGridView getGridView();
+    method public final android.support.v17.leanback.widget.ListRowPresenter getListRowPresenter();
+  }
+
+  public final class ListRowView extends android.widget.LinearLayout {
+    ctor public ListRowView(android.content.Context);
+    ctor public ListRowView(android.content.Context, android.util.AttributeSet);
+    ctor public ListRowView(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v17.leanback.widget.HorizontalGridView getGridView();
+  }
+
+  public abstract class ObjectAdapter {
+    ctor public ObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public ObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public ObjectAdapter();
+    method public abstract java.lang.Object get(int);
+    method public long getId(int);
+    method public final android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+    method public final boolean hasStableIds();
+    method protected final void notifyChanged();
+    method protected final void notifyItemRangeChanged(int, int);
+    method protected final void notifyItemRangeInserted(int, int);
+    method protected final void notifyItemRangeRemoved(int, int);
+    method protected void onHasStableIdsChanged();
+    method protected void onPresenterSelectorChanged();
+    method public final void registerObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+    method public final void setHasStableIds(boolean);
+    method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public abstract int size();
+    method public final void unregisterAllObservers();
+    method public final void unregisterObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+    field public static final int NO_ID = -1; // 0xffffffff
+  }
+
+  public static abstract class ObjectAdapter.DataObserver {
+    ctor public ObjectAdapter.DataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeRemoved(int, int);
+  }
+
+  public abstract interface OnActionClickedListener {
+    method public abstract void onActionClicked(android.support.v17.leanback.widget.Action);
+  }
+
+  public abstract interface OnChildLaidOutListener {
+    method public abstract void onChildLaidOut(android.view.ViewGroup, android.view.View, int, long);
+  }
+
+  public abstract deprecated interface OnChildSelectedListener {
+    method public abstract void onChildSelected(android.view.ViewGroup, android.view.View, int, long);
+  }
+
+  public abstract class OnChildViewHolderSelectedListener {
+    ctor public OnChildViewHolderSelectedListener();
+    method public void onChildViewHolderSelected(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
+  }
+
+  public abstract interface OnItemViewClickedListener {
+    method public abstract void onItemClicked(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public abstract interface OnItemViewSelectedListener {
+    method public abstract void onItemSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+  }
+
+  public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
+    ctor public PlaybackControlsRow(java.lang.Object);
+    ctor public PlaybackControlsRow();
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+    method public android.support.v17.leanback.widget.Action getActionForKeyCode(android.support.v17.leanback.widget.ObjectAdapter, int);
+    method public int getBufferedProgress();
+    method public int getCurrentTime();
+    method public final android.graphics.drawable.Drawable getImageDrawable();
+    method public final java.lang.Object getItem();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getPrimaryActionsAdapter();
+    method public final android.support.v17.leanback.widget.ObjectAdapter getSecondaryActionsAdapter();
+    method public int getTotalTime();
+    method public void setBufferedProgress(int);
+    method public void setCurrentTime(int);
+    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+    method public final void setImageDrawable(android.graphics.drawable.Drawable);
+    method public final void setPrimaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public final void setSecondaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setTotalTime(int);
+  }
+
+  public static class PlaybackControlsRow.ClosedCaptioningAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context);
+    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.FastForwardAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context);
+    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context, int);
+  }
+
+  public static class PlaybackControlsRow.HighQualityAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context);
+    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.MoreActions extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.MoreActions(android.content.Context);
+  }
+
+  public static abstract class PlaybackControlsRow.MultiAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.MultiAction(int);
+    method public int getActionCount();
+    method public android.graphics.drawable.Drawable getDrawable(int);
+    method public int getIndex();
+    method public java.lang.String getLabel(int);
+    method public java.lang.String getSecondaryLabel(int);
+    method public void nextIndex();
+    method public void setDrawables(android.graphics.drawable.Drawable[]);
+    method public void setIndex(int);
+    method public void setLabels(java.lang.String[]);
+    method public void setSecondaryLabels(java.lang.String[]);
+  }
+
+  public static class PlaybackControlsRow.PlayPauseAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.PlayPauseAction(android.content.Context);
+    field public static int PAUSE;
+    field public static int PLAY;
+  }
+
+  public static class PlaybackControlsRow.RepeatAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context);
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int);
+    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int, int);
+    field public static int ALL;
+    field public static int NONE;
+    field public static int ONE;
+  }
+
+  public static class PlaybackControlsRow.RewindAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.RewindAction(android.content.Context);
+    ctor public PlaybackControlsRow.RewindAction(android.content.Context, int);
+  }
+
+  public static class PlaybackControlsRow.ShuffleAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context);
+    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context, int);
+    field public static int OFF;
+    field public static int ON;
+  }
+
+  public static class PlaybackControlsRow.SkipNextAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.SkipNextAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.SkipPreviousAction extends android.support.v17.leanback.widget.Action {
+    ctor public PlaybackControlsRow.SkipPreviousAction(android.content.Context);
+  }
+
+  public static abstract class PlaybackControlsRow.ThumbsAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+    ctor public PlaybackControlsRow.ThumbsAction(int, android.content.Context, int, int);
+    field public static int OUTLINE;
+    field public static int SOLID;
+  }
+
+  public static class PlaybackControlsRow.ThumbsDownAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+    ctor public PlaybackControlsRow.ThumbsDownAction(android.content.Context);
+  }
+
+  public static class PlaybackControlsRow.ThumbsUpAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+    ctor public PlaybackControlsRow.ThumbsUpAction(android.content.Context);
+  }
+
+  public class PlaybackControlsRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public PlaybackControlsRowPresenter(android.support.v17.leanback.widget.Presenter);
+    ctor public PlaybackControlsRowPresenter();
+    method public boolean areSecondaryActionsHidden();
+    method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method public int getBackgroundColor();
+    method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+    method public int getProgressColor();
+    method public void setBackgroundColor(int);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public void setProgressColor(int);
+    method public void setSecondaryActionsHidden(boolean);
+    method public void showBottomSpace(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
+    method public void showPrimaryActions(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
+  }
+
+  public class PlaybackControlsRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDescriptionViewHolder;
+  }
+
+  public abstract class Presenter implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public Presenter();
+    method protected static void cancelAnimationsRecursive(android.view.View);
+    method public final java.lang.Object getFacet(java.lang.Class<?>);
+    method public abstract void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public abstract android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public abstract void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+    method public void setOnClickListener(android.support.v17.leanback.widget.Presenter.ViewHolder, android.view.View.OnClickListener);
+  }
+
+  public static class Presenter.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+    ctor public Presenter.ViewHolder(android.view.View);
+    method public final java.lang.Object getFacet(java.lang.Class<?>);
+    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+    field public final android.view.View view;
+  }
+
+  public abstract class PresenterSelector {
+    ctor public PresenterSelector();
+    method public abstract android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter[] getPresenters();
+  }
+
+  public abstract class PresenterSwitcher {
+    ctor public PresenterSwitcher();
+    method public void clear();
+    method public final android.view.ViewGroup getParentViewGroup();
+    method public void init(android.view.ViewGroup, android.support.v17.leanback.widget.PresenterSelector);
+    method protected abstract void insertView(android.view.View);
+    method protected void onViewSelected(android.view.View);
+    method public void select(java.lang.Object);
+    method protected void showView(android.view.View, boolean);
+    method public void unselect();
+  }
+
+  public class Row {
+    ctor public Row(long, android.support.v17.leanback.widget.HeaderItem);
+    ctor public Row(android.support.v17.leanback.widget.HeaderItem);
+    ctor public Row();
+    method public final android.support.v17.leanback.widget.HeaderItem getHeaderItem();
+    method public final long getId();
+    method public final void setHeaderItem(android.support.v17.leanback.widget.HeaderItem);
+    method public final void setId(long);
+  }
+
+  public class RowHeaderPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public RowHeaderPresenter();
+    method protected static float getFontDescent(android.widget.TextView, android.graphics.Paint);
+    method public int getSpaceUnderBaseline(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+    method public boolean isNullItemVisibilityGone();
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setNullItemVisibilityGone(boolean);
+    method public final void setSelectLevel(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, float);
+  }
+
+  public static class RowHeaderPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public RowHeaderPresenter.ViewHolder(android.view.View);
+    method public final float getSelectLevel();
+  }
+
+  public final class RowHeaderView extends android.widget.TextView {
+    ctor public RowHeaderView(android.content.Context);
+    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet);
+    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public abstract class RowPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public RowPresenter();
+    method protected abstract android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected void dispatchItemSelectedListener(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public void freeze(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public final android.support.v17.leanback.widget.RowHeaderPresenter getHeaderPresenter();
+    method public final android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final boolean getSelectEffectEnabled();
+    method public final float getSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final int getSyncActivatePolicy();
+    method protected void initializeRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected boolean isClippingChildren();
+    method public boolean isUsingDefaultSelectEffect();
+    method protected void onBindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder, java.lang.Object);
+    method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method protected void onRowViewAttachedToWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewDetachedFromWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewExpanded(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method protected void onRowViewSelected(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onUnbindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+    method public final void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public final void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setEntranceTransitionState(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+    method public final void setHeaderPresenter(android.support.v17.leanback.widget.RowHeaderPresenter);
+    method public final void setRowViewExpanded(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+    method public final void setRowViewSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+    method public final void setSelectEffectEnabled(boolean);
+    method public final void setSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder, float);
+    method public final void setSyncActivatePolicy(int);
+    field public static final int SYNC_ACTIVATED_CUSTOM = 0; // 0x0
+    field public static final int SYNC_ACTIVATED_TO_EXPANDED = 1; // 0x1
+    field public static final int SYNC_ACTIVATED_TO_EXPANDED_AND_SELECTED = 3; // 0x3
+    field public static final int SYNC_ACTIVATED_TO_SELECTED = 2; // 0x2
+  }
+
+  public static class RowPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public RowPresenter.ViewHolder(android.view.View);
+    method public final android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder getHeaderViewHolder();
+    method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public android.view.View.OnKeyListener getOnKeyListener();
+    method public final android.support.v17.leanback.widget.Row getRow();
+    method public final float getSelectLevel();
+    method public final boolean isExpanded();
+    method public final boolean isSelected();
+    method public final void setActivated(boolean);
+    method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setOnKeyListener(android.view.View.OnKeyListener);
+    method public final void syncActivatedStatus(android.view.View);
+    field protected final android.support.v17.leanback.graphics.ColorOverlayDimmer mColorDimmer;
+  }
+
+  public class SearchBar extends android.widget.RelativeLayout {
+    ctor public SearchBar(android.content.Context);
+    ctor public SearchBar(android.content.Context, android.util.AttributeSet);
+    ctor public SearchBar(android.content.Context, android.util.AttributeSet, int);
+    method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public java.lang.CharSequence getHint();
+    method public java.lang.String getTitle();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setSearchBarListener(android.support.v17.leanback.widget.SearchBar.SearchBarListener);
+    method public void setSearchQuery(java.lang.String);
+    method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+    method public void setSpeechRecognizer(android.speech.SpeechRecognizer);
+    method public void setTitle(java.lang.String);
+    method public void startRecognition();
+    method public void stopRecognition();
+  }
+
+  public static abstract interface SearchBar.SearchBarListener {
+    method public abstract void onKeyboardDismiss(java.lang.String);
+    method public abstract void onSearchQueryChange(java.lang.String);
+    method public abstract void onSearchQuerySubmit(java.lang.String);
+  }
+
+  public class SearchEditText extends android.support.v17.leanback.widget.StreamingTextView {
+    ctor public SearchEditText(android.content.Context);
+    ctor public SearchEditText(android.content.Context, android.util.AttributeSet);
+    ctor public SearchEditText(android.content.Context, android.util.AttributeSet, int);
+    method public void setOnKeyboardDismissListener(android.support.v17.leanback.widget.SearchEditText.OnKeyboardDismissListener);
+  }
+
+  public static abstract interface SearchEditText.OnKeyboardDismissListener {
+    method public abstract void onKeyboardDismiss();
+  }
+
+  public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
+    ctor public SearchOrbView(android.content.Context);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet, int);
+    method public void enableOrbColorAnimation(boolean);
+    method public int getOrbColor();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getOrbColors();
+    method public android.graphics.drawable.Drawable getOrbIcon();
+    method public void onClick(android.view.View);
+    method public void setOnOrbClickedListener(android.view.View.OnClickListener);
+    method public void setOrbColor(int);
+    method public deprecated void setOrbColor(int, int);
+    method public void setOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setOrbIcon(android.graphics.drawable.Drawable);
+  }
+
+  public static class SearchOrbView.Colors {
+    ctor public SearchOrbView.Colors(int);
+    ctor public SearchOrbView.Colors(int, int);
+    ctor public SearchOrbView.Colors(int, int, int);
+    method public static int getBrightColor(int);
+    field public int brightColor;
+    field public int color;
+    field public int iconColor;
+  }
+
+  public class ShadowOverlayContainer extends android.widget.FrameLayout {
+    ctor public ShadowOverlayContainer(android.content.Context);
+    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet);
+    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int);
+    method public int getShadowType();
+    method public android.view.View getWrappedView();
+    method public deprecated void initialize(boolean, boolean);
+    method public deprecated void initialize(boolean, boolean, boolean);
+    method public static void prepareParentForShadow(android.view.ViewGroup);
+    method public void setOverlayColor(int);
+    method public void setShadowFocusLevel(float);
+    method public static boolean supportsDynamicShadow();
+    method public static boolean supportsShadow();
+    method public void useDynamicShadow();
+    method public void useDynamicShadow(float, float);
+    method public void useStaticShadow();
+    method public void wrap(android.view.View);
+    field public static final int SHADOW_DYNAMIC = 3; // 0x3
+    field public static final int SHADOW_NONE = 1; // 0x1
+    field public static final int SHADOW_STATIC = 2; // 0x2
+  }
+
+  public final class ShadowOverlayHelper {
+    method public android.support.v17.leanback.widget.ShadowOverlayContainer createShadowOverlayContainer(android.content.Context);
+    method public int getShadowType();
+    method public boolean needsOverlay();
+    method public boolean needsRoundedCorner();
+    method public boolean needsWrapper();
+    method public void onViewCreated(android.view.View);
+    method public void prepareParentForShadow(android.view.ViewGroup);
+    method public static void setNoneWrapperOverlayColor(android.view.View, int);
+    method public static void setNoneWrapperShadowFocusLevel(android.view.View, float);
+    method public void setOverlayColor(android.view.View, int);
+    method public void setShadowFocusLevel(android.view.View, float);
+    method public static boolean supportsDynamicShadow();
+    method public static boolean supportsForeground();
+    method public static boolean supportsRoundedCorner();
+    method public static boolean supportsShadow();
+    field public static final int SHADOW_DYNAMIC = 3; // 0x3
+    field public static final int SHADOW_NONE = 1; // 0x1
+    field public static final int SHADOW_STATIC = 2; // 0x2
+  }
+
+  public static final class ShadowOverlayHelper.Builder {
+    ctor public ShadowOverlayHelper.Builder();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper build(android.content.Context);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder keepForegroundDrawable(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsOverlay(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsRoundedCorner(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsShadow(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder options(android.support.v17.leanback.widget.ShadowOverlayHelper.Options);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder preferZOrder(boolean);
+  }
+
+  public static final class ShadowOverlayHelper.Options {
+    ctor public ShadowOverlayHelper.Options();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options dynamicShadowZ(float, float);
+    method public final float getDynamicShadowFocusedZ();
+    method public final float getDynamicShadowUnfocusedZ();
+    method public final int getRoundedCornerRadius();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options roundedCornerRadius(int);
+    field public static final android.support.v17.leanback.widget.ShadowOverlayHelper.Options DEFAULT;
+  }
+
+  public final class SinglePresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+    ctor public SinglePresenterSelector(android.support.v17.leanback.widget.Presenter);
+    method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+  }
+
+  public class SparseArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+    ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+    ctor public SparseArrayObjectAdapter();
+    method public void clear(int);
+    method public void clear();
+    method public java.lang.Object get(int);
+    method public int indexOf(java.lang.Object);
+    method public int indexOf(int);
+    method public java.lang.Object lookup(int);
+    method public void notifyArrayItemRangeChanged(int, int);
+    method public void set(int, java.lang.Object);
+    method public int size();
+  }
+
+  public class SpeechOrbView extends android.support.v17.leanback.widget.SearchOrbView {
+    ctor public SpeechOrbView(android.content.Context);
+    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet);
+    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet, int);
+    method public void setSoundLevel(int);
+    method public void showListening();
+    method public void showNotListening();
+  }
+
+  public abstract interface SpeechRecognitionCallback {
+    method public abstract void recognizeSpeech();
+  }
+
+   class StreamingTextView extends android.widget.EditText {
+    ctor public StreamingTextView(android.content.Context, android.util.AttributeSet);
+    ctor public StreamingTextView(android.content.Context, android.util.AttributeSet, int);
+    method public static boolean isLayoutRtl(android.view.View);
+    method public void reset();
+    method public void setFinalRecognizedText(java.lang.CharSequence);
+    method public void updateRecognizedText(java.lang.String, java.lang.String);
+    method public void updateRecognizedText(java.lang.String, java.util.List<java.lang.Float>);
+  }
+
+  public class TitleHelper {
+    ctor public TitleHelper(android.view.ViewGroup, android.support.v17.leanback.widget.TitleView);
+    method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+    method public android.view.ViewGroup getSceneRoot();
+    method public android.support.v17.leanback.widget.TitleView getTitleView();
+    method public void showTitle(boolean);
+  }
+
+  public class TitleView extends android.widget.FrameLayout {
+    ctor public TitleView(android.content.Context);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet, int);
+    method public void enableAnimation(boolean);
+    method public android.graphics.drawable.Drawable getBadgeDrawable();
+    method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+    method public android.view.View getSearchAffordanceView();
+    method public java.lang.CharSequence getTitle();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(java.lang.String);
+  }
+
+  public class VerticalGridPresenter extends android.support.v17.leanback.widget.Presenter {
+    ctor public VerticalGridPresenter();
+    ctor public VerticalGridPresenter(int);
+    ctor public VerticalGridPresenter(int, boolean);
+    method public final boolean areChildRoundedCornersEnabled();
+    method protected android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder createGridViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+    method public final void enableChildRoundedCorners(boolean);
+    method public final int getFocusZoomFactor();
+    method public final boolean getKeepChildForeground();
+    method public int getNumberOfColumns();
+    method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+    method public final boolean getShadowEnabled();
+    method protected void initializeGridViewHolder(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder);
+    method public final boolean isFocusDimmerUsed();
+    method public boolean isUsingDefaultShadow();
+    method public boolean isUsingZOrder(android.content.Context);
+    method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+    method public final android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setEntranceTransitionState(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder, boolean);
+    method public final void setKeepChildForeground(boolean);
+    method public void setNumberOfColumns(int);
+    method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public final void setShadowEnabled(boolean);
+  }
+
+  public static class VerticalGridPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+    ctor public VerticalGridPresenter.ViewHolder(android.support.v17.leanback.widget.VerticalGridView);
+    method public android.support.v17.leanback.widget.VerticalGridView getGridView();
+  }
+
+  public class VerticalGridView extends android.support.v7.widget.RecyclerView {
+    ctor public VerticalGridView(android.content.Context);
+    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet);
+    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet, int);
+    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+    method public void setColumnWidth(int);
+    method public void setNumColumns(int);
+  }
+
+}
+
diff --git a/v17/leanback/api/current.txt b/v17/leanback/api/current.txt
index fb2832d..a4decd8 100644
--- a/v17/leanback/api/current.txt
+++ b/v17/leanback/api/current.txt
@@ -37,6 +37,7 @@
   public class BrowseFragment extends android.support.v17.leanback.app.BrandedFragment {
     ctor public BrowseFragment();
     method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
     method public void enableRowScaling(boolean);
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public int getBrandColor();
@@ -46,6 +47,12 @@
     method public final boolean isHeadersTransitionOnBackEnabled();
     method public boolean isInHeadersTransition();
     method public boolean isShowingHeaders();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method public void onSaveInstanceState(android.os.Bundle);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
     method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setBrandColor(int);
     method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseFragment.BrowseTransitionListener);
@@ -71,6 +78,7 @@
   public class BrowseSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
     ctor public BrowseSupportFragment();
     method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+    method protected java.lang.Object createEntranceTransition();
     method public void enableRowScaling(boolean);
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public int getBrandColor();
@@ -80,6 +88,12 @@
     method public final boolean isHeadersTransitionOnBackEnabled();
     method public boolean isInHeadersTransition();
     method public boolean isShowingHeaders();
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
+    method public void onSaveInstanceState(android.os.Bundle);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
     method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setBrandColor(int);
     method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseSupportFragment.BrowseTransitionListener);
@@ -104,11 +118,17 @@
 
   public class DetailsFragment extends android.support.v17.leanback.app.BrandedFragment {
     ctor public DetailsFragment();
+    method protected java.lang.Object createEntranceTransition();
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
     method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
     method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
     method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
     method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
     method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
@@ -120,11 +140,17 @@
 
   public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
     ctor public DetailsSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
     method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method protected void onEntranceTransitionEnd();
+    method protected void onEntranceTransitionPrepare();
+    method protected void onEntranceTransitionStart();
     method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
     method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+    method public void onStart();
+    method protected void runEntranceTransition(java.lang.Object);
     method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
     method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
@@ -177,23 +203,109 @@
   public class GuidedStepFragment extends android.app.Fragment {
     ctor public GuidedStepFragment();
     method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment);
+    method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public static int addAsRoot(android.app.Activity, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+    method public int findActionPositionById(long);
+    method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+    method public int findButtonActionPositionById(long);
+    method public void finishGuidedStepFragments();
+    method public java.lang.String generateStackEntryName();
+    method public static java.lang.String generateStackEntryName(int, java.lang.Class);
     method public android.view.View getActionItemView(int);
     method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method public android.view.View getButtonActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
     method public static android.support.v17.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
     method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
     method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+    method public static java.lang.String getGuidedStepFragmentClassName(java.lang.String);
     method public int getSelectedActionPosition();
-    method protected boolean isEntryTransitionEnabled();
+    method public int getSelectedButtonActionPosition();
+    method public int getUiStyle();
+    method public static boolean isUiStyleDefault(java.lang.String);
+    method public static boolean isUiStyleEntrance(java.lang.String);
+    method public void notifyActionChanged(int);
+    method public void notifyButtonActionChanged(int);
+    method protected void onAddSharedElementTransition(android.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepFragment);
     method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
     method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
     method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
     method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
     method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
     method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected void onProvideFragmentTransitions();
     method public int onProvideTheme();
+    method public void popBackStackToGuidedStepFragment(java.lang.Class, int);
     method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
-    method protected void setEntryTransitionEnabled(boolean);
+    method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
     method public void setSelectedActionPosition(int);
+    method public void setSelectedButtonActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+    field public static final int UI_STYLE_REPLACE = 0; // 0x0
+  }
+
+  public class GuidedStepSupportFragment extends android.support.v4.app.Fragment {
+    ctor public GuidedStepSupportFragment();
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment);
+    method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public static int addAsRoot(android.support.v4.app.FragmentActivity, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+    method public int findActionPositionById(long);
+    method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+    method public int findButtonActionPositionById(long);
+    method public void finishGuidedStepSupportFragments();
+    method public java.lang.String generateStackEntryName();
+    method public static java.lang.String generateStackEntryName(int, java.lang.Class);
+    method public android.view.View getActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+    method public android.view.View getButtonActionItemView(int);
+    method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
+    method public static android.support.v17.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(android.support.v4.app.FragmentManager);
+    method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+    method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+    method public static java.lang.String getGuidedStepSupportFragmentClassName(java.lang.String);
+    method public int getSelectedActionPosition();
+    method public int getSelectedButtonActionPosition();
+    method public int getUiStyle();
+    method public static boolean isUiStyleDefault(java.lang.String);
+    method public static boolean isUiStyleEntrance(java.lang.String);
+    method public void notifyActionChanged(int);
+    method public void notifyButtonActionChanged(int);
+    method protected void onAddSharedElementTransition(android.support.v4.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepSupportFragment);
+    method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
+    method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+    method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+    method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+    method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
+    method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+    method protected void onProvideFragmentTransitions();
+    method public int onProvideTheme();
+    method public void popBackStackToGuidedStepSupportFragment(java.lang.Class, int);
+    method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+    method public void setSelectedActionPosition(int);
+    method public void setSelectedButtonActionPosition(int);
+    method public void setUiStyle(int);
+    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+    field public static final int UI_STYLE_REPLACE = 0; // 0x0
   }
 
   public class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
@@ -300,12 +412,69 @@
     field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
   }
 
+  public abstract class PlaybackControlSupportGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, int[], int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[]);
+    ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[], int[]);
+    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+    method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+    method public void enableProgressUpdating(boolean);
+    method public android.content.Context getContext();
+    method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+    method public abstract int getCurrentPosition();
+    method public abstract int getCurrentSpeedId();
+    method public int[] getFastForwardSpeeds();
+    method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment getFragment();
+    method public abstract android.graphics.drawable.Drawable getMediaArt();
+    method public abstract int getMediaDuration();
+    method public abstract java.lang.CharSequence getMediaSubtitle();
+    method public abstract java.lang.CharSequence getMediaTitle();
+    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public int[] getRewindSpeeds();
+    method public abstract long getSupportedActions();
+    method public int getUpdatePeriod();
+    method public abstract boolean hasValidMedia();
+    method public boolean isFadingEnabled();
+    method public abstract boolean isMediaPlaying();
+    method public void onActionClicked(android.support.v17.leanback.widget.Action);
+    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+    method protected void onMetadataChanged();
+    method protected abstract void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method protected void onStateChanged();
+    method protected abstract void pausePlayback();
+    method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+    method public void setFadingEnabled(boolean);
+    method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+    method protected abstract void skipToNext();
+    method protected abstract void skipToPrevious();
+    method protected abstract void startPlayback(int);
+    method public void updateProgress();
+    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+    field public static final int ACTION_REWIND = 32; // 0x20
+    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+  }
+
   public class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
     ctor public PlaybackOverlayFragment();
     method public int getBackgroundType();
     method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
     method public final android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
     method public boolean isFadingEnabled();
+    method public void onDestroyView();
+    method public void onResume();
     method public void setBackgroundType(int);
     method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
     method public void setFadingEnabled(boolean);
@@ -332,6 +501,8 @@
     method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener getFadeCompleteListener();
     method public final android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
     method public boolean isFadingEnabled();
+    method public void onDestroyView();
+    method public void onResume();
     method public void setBackgroundType(int);
     method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener);
     method public void setFadingEnabled(boolean);
@@ -379,6 +550,7 @@
     method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
     method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
     method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
     method public android.graphics.drawable.Drawable getBadgeDrawable();
     method public android.content.Intent getRecognizerIntent();
     method public java.lang.String getTitle();
@@ -405,6 +577,7 @@
     method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
     method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
     method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
     method public android.graphics.drawable.Drawable getBadgeDrawable();
     method public android.content.Intent getRecognizerIntent();
     method public java.lang.String getTitle();
@@ -426,11 +599,16 @@
     method public abstract boolean onQueryTextSubmit(java.lang.String);
   }
 
-  public class VerticalGridFragment extends android.app.Fragment {
+  public class VerticalGridFragment extends android.support.v17.leanback.app.BrandedFragment {
     ctor public VerticalGridFragment();
+    method protected java.lang.Object createEntranceTransition();
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
     method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public void onDestroyView();
+    method public void onStart();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
+    method protected void runEntranceTransition(java.lang.Object);
     method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
@@ -438,11 +616,16 @@
     method public void setSelectedPosition(int);
   }
 
-  public class VerticalGridSupportFragment extends android.support.v4.app.Fragment {
+  public class VerticalGridSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
     ctor public VerticalGridSupportFragment();
+    method protected java.lang.Object createEntranceTransition();
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
     method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public void onDestroyView();
+    method public void onStart();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
+    method protected void runEntranceTransition(java.lang.Object);
     method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
@@ -722,12 +905,8 @@
   }
 
   public abstract interface FragmentAnimationProvider {
-    method public abstract void onActivityEnter(java.util.List<android.animation.Animator>);
-    method public abstract void onActivityExit(java.util.List<android.animation.Animator>);
-    method public abstract void onFragmentEnter(java.util.List<android.animation.Animator>);
-    method public abstract void onFragmentExit(java.util.List<android.animation.Animator>);
-    method public abstract void onFragmentReenter(java.util.List<android.animation.Animator>);
-    method public abstract void onFragmentReturn(java.util.List<android.animation.Animator>);
+    method public abstract void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public abstract void onImeDisappearing(java.util.List<android.animation.Animator>);
   }
 
   public class FullWidthDetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
@@ -798,13 +977,10 @@
     method public android.widget.TextView getDescriptionView();
     method public android.widget.ImageView getIconView();
     method public android.widget.TextView getTitleView();
-    method public void onActivityEnter(java.util.List<android.animation.Animator>);
-    method public void onActivityExit(java.util.List<android.animation.Animator>);
     method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.support.v17.leanback.widget.GuidanceStylist.Guidance);
-    method public void onFragmentEnter(java.util.List<android.animation.Animator>);
-    method public void onFragmentExit(java.util.List<android.animation.Animator>);
-    method public void onFragmentReenter(java.util.List<android.animation.Animator>);
-    method public void onFragmentReturn(java.util.List<android.animation.Animator>);
+    method public void onDestroyView();
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
     method public int onProvideLayoutId();
   }
 
@@ -817,59 +993,112 @@
   }
 
   public class GuidedAction extends android.support.v17.leanback.widget.Action {
+    ctor protected GuidedAction();
     method public int getCheckSetId();
     method public java.lang.CharSequence getDescription();
+    method public int getDescriptionEditInputType();
+    method public int getDescriptionInputType();
+    method public java.lang.CharSequence getEditDescription();
+    method public int getEditInputType();
+    method public java.lang.CharSequence getEditTitle();
+    method public int getInputType();
     method public android.content.Intent getIntent();
     method public java.lang.CharSequence getTitle();
     method public boolean hasMultilineDescription();
     method public boolean hasNext();
     method public boolean infoOnly();
     method public boolean isChecked();
+    method public boolean isDescriptionEditable();
+    method public boolean isEditTitleUsed();
+    method public boolean isEditable();
     method public boolean isEnabled();
+    method public boolean isFocusable();
     method public void setChecked(boolean);
+    method public void setDescription(java.lang.CharSequence);
+    method public void setEditDescription(java.lang.CharSequence);
+    method public void setEditTitle(java.lang.CharSequence);
     method public void setEnabled(boolean);
+    method public void setFocusable(boolean);
+    method public void setTitle(java.lang.CharSequence);
+    field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
+    field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
+    field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
+    field public static final long ACTION_ID_FINISH = -6L; // 0xfffffffffffffffaL
+    field public static final long ACTION_ID_NEXT = -2L; // 0xfffffffffffffffeL
+    field public static final long ACTION_ID_NO = -9L; // 0xfffffffffffffff7L
+    field public static final long ACTION_ID_OK = -4L; // 0xfffffffffffffffcL
+    field public static final long ACTION_ID_YES = -8L; // 0xfffffffffffffff8L
+    field public static final int CHECKBOX_CHECK_SET_ID = -1; // 0xffffffff
     field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
     field public static final int NO_CHECK_SET = 0; // 0x0
-    field public static final int NO_DRAWABLE = 0; // 0x0
   }
 
   public static class GuidedAction.Builder {
     ctor public GuidedAction.Builder();
-    method public android.support.v17.leanback.widget.GuidedAction build();
+    method protected final void applyValues(android.support.v17.leanback.widget.GuidedAction);
+    method public final android.support.v17.leanback.widget.GuidedAction build();
     method public android.support.v17.leanback.widget.GuidedAction.Builder checkSetId(int);
     method public android.support.v17.leanback.widget.GuidedAction.Builder checked(boolean);
-    method public android.support.v17.leanback.widget.GuidedAction.Builder description(java.lang.String);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder constructCancel(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder constructContinue(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder constructFinish(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder constructNo(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder constructOK(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder constructYes(android.content.Context);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder description(java.lang.CharSequence);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder descriptionEditInputType(int);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder descriptionEditable(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder descriptionInputType(int);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder editDescription(java.lang.CharSequence);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder editInputType(int);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder editTitle(java.lang.CharSequence);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder editable(boolean);
     method public android.support.v17.leanback.widget.GuidedAction.Builder enabled(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder focusable(boolean);
     method public android.support.v17.leanback.widget.GuidedAction.Builder hasNext(boolean);
     method public android.support.v17.leanback.widget.GuidedAction.Builder icon(android.graphics.drawable.Drawable);
     method public android.support.v17.leanback.widget.GuidedAction.Builder iconResourceId(int, android.content.Context);
     method public android.support.v17.leanback.widget.GuidedAction.Builder id(long);
     method public android.support.v17.leanback.widget.GuidedAction.Builder infoOnly(boolean);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder inputType(int);
     method public android.support.v17.leanback.widget.GuidedAction.Builder intent(android.content.Intent);
     method public android.support.v17.leanback.widget.GuidedAction.Builder multilineDescription(boolean);
-    method public android.support.v17.leanback.widget.GuidedAction.Builder title(java.lang.String);
+    method public android.support.v17.leanback.widget.GuidedAction.Builder title(java.lang.CharSequence);
+  }
+
+  public class GuidedActionEditText extends android.widget.EditText implements android.support.v17.leanback.widget.ImeKeyMonitor {
+    ctor public GuidedActionEditText(android.content.Context);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet);
+    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet, int);
+    method public void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
   }
 
   public class GuidedActionsStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
     ctor public GuidedActionsStylist();
     method public android.support.v17.leanback.widget.VerticalGridView getActionsGridView();
-    method public void onActivityEnter(java.util.List<android.animation.Animator>);
-    method public void onActivityExit(java.util.List<android.animation.Animator>);
+    method public int getItemViewType(android.support.v17.leanback.widget.GuidedAction);
+    method public boolean isButtonActions();
     method public void onAnimateItemChecked(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
     method public void onAnimateItemFocused(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
     method public void onAnimateItemPressed(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+    method public void onAnimateItemPressedCancelled(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public void onBindCheckMarkView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    method public void onBindChevronView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
     method public void onBindViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
     method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
     method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method public void onFragmentEnter(java.util.List<android.animation.Animator>);
-    method public void onFragmentExit(java.util.List<android.animation.Animator>);
-    method public void onFragmentReenter(java.util.List<android.animation.Animator>);
-    method public void onFragmentReturn(java.util.List<android.animation.Animator>);
+    method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDestroyView();
+    method protected void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method public void onImeAppearing(java.util.List<android.animation.Animator>);
+    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
     method public int onProvideItemLayoutId();
+    method public int onProvideItemLayoutId(int);
     method public int onProvideLayoutId();
-    field protected android.support.v17.leanback.widget.VerticalGridView mActionsGridView;
-    field protected android.view.View mMainView;
-    field protected android.view.View mSelectorView;
+    method public void setAsButtonActions();
+    method public void setEditingMode(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method protected void setupImeOptions(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+    field public static final int VIEW_TYPE_DEFAULT = 0; // 0x0
   }
 
   public static class GuidedActionsStylist.ViewHolder {
@@ -878,8 +1107,13 @@
     method public android.widget.ImageView getChevronView();
     method public android.view.View getContentView();
     method public android.widget.TextView getDescriptionView();
+    method public android.widget.EditText getEditableDescriptionView();
+    method public android.widget.EditText getEditableTitleView();
+    method public android.view.View getEditingView();
     method public android.widget.ImageView getIconView();
     method public android.widget.TextView getTitleView();
+    method public boolean isInEditing();
+    method public boolean isInEditingDescription();
     field public final android.view.View view;
   }
 
@@ -918,9 +1152,10 @@
   }
 
   public class ImageCardView extends android.support.v17.leanback.widget.BaseCardView {
+    ctor public ImageCardView(android.content.Context, int);
+    ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
     ctor public ImageCardView(android.content.Context);
     ctor public ImageCardView(android.content.Context, android.util.AttributeSet);
-    ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
     method public android.graphics.drawable.Drawable getBadgeImage();
     method public java.lang.CharSequence getContentText();
     method public android.graphics.drawable.Drawable getInfoAreaBackground();
@@ -937,6 +1172,19 @@
     method public void setMainImageDimensions(int, int);
     method public void setMainImageScaleType(android.widget.ImageView.ScaleType);
     method public void setTitleText(java.lang.CharSequence);
+    field public static final int CARD_TYPE_FLAG_CONTENT = 2; // 0x2
+    field public static final int CARD_TYPE_FLAG_ICON_LEFT = 8; // 0x8
+    field public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4; // 0x4
+    field public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0; // 0x0
+    field public static final int CARD_TYPE_FLAG_TITLE = 1; // 0x1
+  }
+
+  public abstract interface ImeKeyMonitor {
+    method public abstract void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+  }
+
+  public static abstract interface ImeKeyMonitor.ImeKeyListener {
+    method public abstract boolean onKeyPreIme(android.widget.EditText, int, android.view.KeyEvent);
   }
 
   public final class ItemAlignmentFacet {
@@ -1012,6 +1260,12 @@
     method public abstract void wrap(android.view.View, android.view.View);
   }
 
+  public class ItemBridgeAdapterShadowOverlayWrapper extends android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper {
+    ctor public ItemBridgeAdapterShadowOverlayWrapper(android.support.v17.leanback.widget.ShadowOverlayHelper);
+    method public android.view.View createWrapper(android.view.View);
+    method public void wrap(android.view.View, android.view.View);
+  }
+
   public class ListRow extends android.support.v17.leanback.widget.Row {
     ctor public ListRow(android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
     ctor public ListRow(long, android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
@@ -1035,6 +1289,7 @@
     ctor public ListRowPresenter(int, boolean);
     method public final boolean areChildRoundedCornersEnabled();
     method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
     method public final void enableChildRoundedCorners(boolean);
     method public int getExpandedRowHeight();
     method public final int getFocusZoomFactor();
@@ -1044,12 +1299,14 @@
     method public final boolean getShadowEnabled();
     method public final deprecated int getZoomFactor();
     method public final boolean isFocusDimmerUsed();
+    method public final boolean isKeepChildForeground();
     method public boolean isUsingDefaultListSelectEffect();
     method public final boolean isUsingDefaultSelectEffect();
     method public boolean isUsingDefaultShadow();
     method public boolean isUsingZOrder(android.content.Context);
     method public void setExpandedRowHeight(int);
     method public final void setHoverCardPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+    method public final void setKeepChildForeground(boolean);
     method public void setRecycledPoolSize(android.support.v17.leanback.widget.Presenter, int);
     method public void setRowHeight(int);
     method public final void setShadowEnabled(boolean);
@@ -1327,7 +1584,6 @@
 
   public abstract class RowPresenter extends android.support.v17.leanback.widget.Presenter {
     ctor public RowPresenter();
-    method public boolean canDrawOutOfBounds();
     method protected abstract android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
     method protected void dispatchItemSelectedListener(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
     method public void freeze(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
@@ -1387,6 +1643,7 @@
     ctor public SearchBar(android.content.Context, android.util.AttributeSet);
     ctor public SearchBar(android.content.Context, android.util.AttributeSet, int);
     method public void displayCompletions(java.util.List<java.lang.String>);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
     method public android.graphics.drawable.Drawable getBadgeDrawable();
     method public java.lang.CharSequence getHint();
     method public java.lang.String getTitle();
@@ -1443,15 +1700,14 @@
     field public int iconColor;
   }
 
-  public class ShadowOverlayContainer extends android.view.ViewGroup {
+  public class ShadowOverlayContainer extends android.widget.FrameLayout {
     ctor public ShadowOverlayContainer(android.content.Context);
     ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet);
     ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int);
     method public int getShadowType();
     method public android.view.View getWrappedView();
     method public deprecated void initialize(boolean, boolean);
-    method public void initialize(boolean, boolean, boolean);
-    method protected void onLayout(boolean, int, int, int, int);
+    method public deprecated void initialize(boolean, boolean, boolean);
     method public static void prepareParentForShadow(android.view.ViewGroup);
     method public void setOverlayColor(int);
     method public void setShadowFocusLevel(float);
@@ -1466,6 +1722,48 @@
     field public static final int SHADOW_STATIC = 2; // 0x2
   }
 
+  public final class ShadowOverlayHelper {
+    method public android.support.v17.leanback.widget.ShadowOverlayContainer createShadowOverlayContainer(android.content.Context);
+    method public int getShadowType();
+    method public boolean needsOverlay();
+    method public boolean needsRoundedCorner();
+    method public boolean needsWrapper();
+    method public void onViewCreated(android.view.View);
+    method public void prepareParentForShadow(android.view.ViewGroup);
+    method public static void setNoneWrapperOverlayColor(android.view.View, int);
+    method public static void setNoneWrapperShadowFocusLevel(android.view.View, float);
+    method public void setOverlayColor(android.view.View, int);
+    method public void setShadowFocusLevel(android.view.View, float);
+    method public static boolean supportsDynamicShadow();
+    method public static boolean supportsForeground();
+    method public static boolean supportsRoundedCorner();
+    method public static boolean supportsShadow();
+    field public static final int SHADOW_DYNAMIC = 3; // 0x3
+    field public static final int SHADOW_NONE = 1; // 0x1
+    field public static final int SHADOW_STATIC = 2; // 0x2
+  }
+
+  public static final class ShadowOverlayHelper.Builder {
+    ctor public ShadowOverlayHelper.Builder();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper build(android.content.Context);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder keepForegroundDrawable(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsOverlay(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsRoundedCorner(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsShadow(boolean);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder options(android.support.v17.leanback.widget.ShadowOverlayHelper.Options);
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder preferZOrder(boolean);
+  }
+
+  public static final class ShadowOverlayHelper.Options {
+    ctor public ShadowOverlayHelper.Options();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options dynamicShadowZ(float, float);
+    method public final float getDynamicShadowFocusedZ();
+    method public final float getDynamicShadowUnfocusedZ();
+    method public final int getRoundedCornerRadius();
+    method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options roundedCornerRadius(int);
+    field public static final android.support.v17.leanback.widget.ShadowOverlayHelper.Options DEFAULT;
+  }
+
   public final class SinglePresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
     ctor public SinglePresenterSelector(android.support.v17.leanback.widget.Presenter);
     method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
@@ -1538,8 +1836,10 @@
     ctor public VerticalGridPresenter(int, boolean);
     method public final boolean areChildRoundedCornersEnabled();
     method protected android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder createGridViewHolder(android.view.ViewGroup);
+    method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
     method public final void enableChildRoundedCorners(boolean);
     method public final int getFocusZoomFactor();
+    method public final boolean getKeepChildForeground();
     method public int getNumberOfColumns();
     method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
     method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
@@ -1551,6 +1851,8 @@
     method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
     method public final android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
     method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+    method public void setEntranceTransitionState(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder, boolean);
+    method public final void setKeepChildForeground(boolean);
     method public void setNumberOfColumns(int);
     method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
     method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
new file mode 100644
index 0000000..1762c15
--- /dev/null
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.TimeInterpolator;
+import android.transition.Fade;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+
+/**
+ * Execute horizontal slide of 1/4 width and fade (to workaround bug 23718734)
+ * @hide
+ */
+public class FadeAndShortSlide extends Visibility {
+
+    private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
+    // private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
+    private static final String PROPNAME_SCREEN_POSITION =
+            "android:fadeAndShortSlideTransition:screenPosition";
+
+    private CalculateSlide mSlideCalculator = sCalculateEnd;
+    private Visibility mFade = new Fade();
+
+    private interface CalculateSlide {
+
+        /** Returns the translation value for view when it goes out of the scene */
+        float getGoneX(ViewGroup sceneRoot, View view, int[] position);
+    }
+
+    private static final CalculateSlide sCalculateStart = new CalculateSlide() {
+        @Override
+        public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            final float x;
+            if (isRtl) {
+                x = view.getTranslationX() + sceneRoot.getWidth() / 4;
+            } else {
+                x = view.getTranslationX() - sceneRoot.getWidth() / 4;
+            }
+            return x;
+        }
+    };
+
+    private static final CalculateSlide sCalculateEnd = new CalculateSlide() {
+        @Override
+        public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            final float x;
+            if (isRtl) {
+                x = view.getTranslationX() - sceneRoot.getWidth() / 4;
+            } else {
+                x = view.getTranslationX() + sceneRoot.getWidth() / 4;
+            }
+            return x;
+        }
+    };
+
+    private static final CalculateSlide sCalculateBoth = new CalculateSlide() {
+
+        @Override
+        public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+            final int viewCenter = position[0] + view.getWidth() / 2;
+            sceneRoot.getLocationOnScreen(position);
+            final int sceneRootCenter = position[0] + sceneRoot.getWidth() / 2;
+            if (viewCenter < sceneRootCenter) {
+                return view.getTranslationX() - sceneRoot.getWidth() / 2;
+            } else {
+                return view.getTranslationX() + sceneRoot.getWidth() / 2;
+            }
+        }
+    };
+
+    public FadeAndShortSlide() {
+        this(Gravity.START);
+    }
+
+    public FadeAndShortSlide(int slideEdge) {
+        setSlideEdge(slideEdge);
+    }
+
+    @Override
+    public void setEpicenterCallback(EpicenterCallback epicenterCallback) {
+        super.setEpicenterCallback(epicenterCallback);
+        mFade.setEpicenterCallback(epicenterCallback);
+    }
+
+    private void captureValues(TransitionValues transitionValues) {
+        View view = transitionValues.view;
+        int[] position = new int[2];
+        view.getLocationOnScreen(position);
+        transitionValues.values.put(PROPNAME_SCREEN_POSITION, position);
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        super.captureStartValues(transitionValues);
+        mFade.captureStartValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        super.captureEndValues(transitionValues);
+        mFade.captureEndValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    public void setSlideEdge(int slideEdge) {
+        switch (slideEdge) {
+            case Gravity.START:
+                mSlideCalculator = sCalculateStart;
+                break;
+            case Gravity.END:
+                mSlideCalculator = sCalculateEnd;
+                break;
+            case Gravity.START | Gravity.END:
+                mSlideCalculator = sCalculateBoth;
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid slide direction");
+        }
+        // SidePropagation propagation = new SidePropagation();
+        // propagation.setSide(slideEdge);
+        // setPropagation(propagation);
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (endValues == null) {
+            return null;
+        }
+        if (sceneRoot == view) {
+            // workaround b/25375640, avoid run animation on sceneRoot
+            return null;
+        }
+        int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
+        int left = position[0];
+        float endX = view.getTranslationX();
+        float startX = mSlideCalculator.getGoneX(sceneRoot, view, position);
+        final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view, endValues,
+                left, startX, endX, sDecelerate, this);
+        final AnimatorSet set = new AnimatorSet();
+        set.play(slideAnimator).with(mFade.onAppear(sceneRoot, view, startValues, endValues));
+
+        return set;
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues == null) {
+            return null;
+        }
+        if (sceneRoot == view) {
+            // workaround b/25375640, avoid run animation on sceneRoot
+            return null;
+        }
+        int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
+        int left = position[0];
+        float startX = view.getTranslationX();
+        float endX = mSlideCalculator.getGoneX(sceneRoot, view, position);
+        final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view,
+                startValues, left, startX, endX, sDecelerate /* sAccelerate */, this);
+        final AnimatorSet set = new AnimatorSet();
+        set.play(slideAnimator).with(mFade.onDisappear(sceneRoot, view, startValues, endValues));
+
+        return set;
+    }
+
+    @Override
+    public Transition addListener(TransitionListener listener) {
+        mFade.addListener(listener);
+        return super.addListener(listener);
+    }
+
+    @Override
+    public Transition removeListener(TransitionListener listener) {
+        mFade.removeListener(listener);
+        return super.removeListener(listener);
+    }
+
+    @Override
+    public Transition clone() {
+        FadeAndShortSlide clone = null;
+        clone = (FadeAndShortSlide) super.clone();
+        clone.mFade = (Visibility) mFade.clone();
+        return clone;
+    }
+}
+
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
index 00ebf4c..c5a33cb 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
@@ -14,8 +14,12 @@
 package android.support.v17.leanback.transition;
 
 import android.R;
+import android.app.Fragment;
 import android.content.Context;
 import android.transition.ChangeTransform;
+import android.transition.Transition;
+import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
 import android.view.animation.AnimationUtils;
 
@@ -24,6 +28,24 @@
     TransitionHelperApi21() {
     }
 
+    public static void setEnterTransition(android.app.Fragment fragment, Object transition) {
+        fragment.setEnterTransition((Transition)transition);
+    }
+
+    public static void setExitTransition(android.app.Fragment fragment, Object transition) {
+       fragment.setExitTransition((Transition)transition);
+    }
+
+    public static void setSharedElementEnterTransition(android.app.Fragment fragment,
+            Object transition) {
+        fragment.setSharedElementEnterTransition((Transition)transition);
+     }
+
+    public static void addSharedElement(android.app.FragmentTransaction ft,
+            View view, String transitionName) {
+        ft.addSharedElement(view, transitionName);
+    }
+
     public static Object getSharedElementEnterTransition(Window window) {
         return window.getSharedElementEnterTransition();
     }
@@ -63,4 +85,12 @@
     public static Object createDefaultInterpolator(Context context) {
         return AnimationUtils.loadInterpolator(context, R.interpolator.fast_out_linear_in);
     }
+
+    public static Object createFadeAndShortSlide(int edge) {
+        return new FadeAndShortSlide(edge);
+    }
+
+    public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+        viewGroup.setTransitionGroup(transitionGroup);
+    }
 }
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
new file mode 100644
index 0000000..2cc35452
--- /dev/null
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
@@ -0,0 +1,128 @@
+package android.support.v17.leanback.transition;
+
+import android.support.v17.leanback.R;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.graphics.Path;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.view.View;
+
+/**
+ * This class is used by Slide and Explode to create an animator that goes from the start position
+ * to the end position. It takes into account the canceled position so that it will not blink out or
+ * shift suddenly when the transition is interrupted.
+ * @hide
+ */
+class TranslationAnimationCreator {
+
+    /**
+     * Creates an animator that can be used for x and/or y translations. When interrupted, it sets a
+     * tag to keep track of the position so that it may be continued from position.
+     *
+     * @param view The view being moved. This may be in the overlay for onDisappear.
+     * @param values The values containing the view in the view hierarchy.
+     * @param viewPosX The x screen coordinate of view
+     * @param startX The start translation x of view
+     * @param endX The end translation x of view
+     * @param interpolator The interpolator to use with this animator.
+     * @return An animator that moves from (startX, startY) to (endX, endY) unless there was a
+     *         previous interruption, in which case it moves from the current position to (endX,
+     *         endY).
+     */
+    static Animator createAnimation(View view, TransitionValues values, int viewPosX, float startX,
+            float endX, TimeInterpolator interpolator, Transition transition) {
+        float terminalX = view.getTranslationX();
+        Integer startPosition = (Integer) values.view.getTag(R.id.transitionPosition);
+        if (startPosition != null) {
+            startX = startPosition - viewPosX + terminalX;
+        }
+        // Initial position is at translation startX, startY, so position is offset by that
+        // amount
+        int startPosX = viewPosX + Math.round(startX - terminalX);
+
+        view.setTranslationX(startX);
+        if (startX == endX) {
+            return null;
+        }
+        float y = view.getTranslationY();
+        Path path = new Path();
+        path.moveTo(startX, y);
+        path.lineTo(endX, y);
+        ObjectAnimator anim =
+                ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y, path);
+
+        TransitionPositionListener listener =
+                new TransitionPositionListener(view, values.view, startPosX, terminalX);
+        transition.addListener(listener);
+        anim.addListener(listener);
+        anim.addPauseListener(listener);
+        anim.setInterpolator(interpolator);
+        return anim;
+    }
+
+    private static class TransitionPositionListener extends AnimatorListenerAdapter
+            implements Transition.TransitionListener {
+
+        private final View mViewInHierarchy;
+        private final View mMovingView;
+        private final int mStartX;
+        private Integer mTransitionPosition;
+        private float mPausedX;
+        private final float mTerminalX;
+
+        private TransitionPositionListener(View movingView, View viewInHierarchy, int startX,
+                float terminalX) {
+            mMovingView = movingView;
+            mViewInHierarchy = viewInHierarchy;
+            mStartX = startX - Math.round(mMovingView.getTranslationX());
+            mTerminalX = terminalX;
+            mTransitionPosition = (Integer) mViewInHierarchy.getTag(R.id.transitionPosition);
+            if (mTransitionPosition != null) {
+                mViewInHierarchy.setTag(R.id.transitionPosition, null);
+            }
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mTransitionPosition = Math.round(mStartX + mMovingView.getTranslationX());
+            mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition);
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animator) {}
+
+        @Override
+        public void onAnimationPause(Animator animator) {
+            mPausedX = mMovingView.getTranslationX();
+            mMovingView.setTranslationX(mTerminalX);
+        }
+
+        @Override
+        public void onAnimationResume(Animator animator) {
+            mMovingView.setTranslationX(mPausedX);
+        }
+
+        @Override
+        public void onTransitionStart(Transition transition) {}
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            mMovingView.setTranslationX(mTerminalX);
+        }
+
+        @Override
+        public void onTransitionCancel(Transition transition) {}
+
+        @Override
+        public void onTransitionPause(Transition transition) {}
+
+        @Override
+        public void onTransitionResume(Transition transition) {}
+    }
+
+}
+
diff --git a/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
index c7fa0f3..a013ba1 100644
--- a/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
@@ -13,31 +13,47 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.support.v17.leanback.R;
-import android.graphics.Color;
+import android.util.SparseArray;
 import android.graphics.Outline;
-import android.graphics.drawable.GradientDrawable;
 import android.view.ViewOutlineProvider;
 import android.view.View;
 
 class RoundedRectHelperApi21 {
 
-    private static int sCornerRadius;
+    private static SparseArray<ViewOutlineProvider> sRoundedRectProvider;
+    private static final int MAX_CACHED_PROVIDER = 32;
 
-    private static final ViewOutlineProvider sOutlineProvider = new ViewOutlineProvider() {
+    static final class RoundedRectOutlineProvider extends ViewOutlineProvider {
+
+        private int mRadius;
+
+        RoundedRectOutlineProvider(int radius) {
+            mRadius = radius;
+        }
+
         @Override
         public void getOutline(View view, Outline outline) {
-            if (sCornerRadius == 0) {
-                sCornerRadius = view.getResources().getDimensionPixelSize(
-                        R.dimen.lb_rounded_rect_corner_radius);
-            }
-            outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), sCornerRadius);
+            outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mRadius);
             outline.setAlpha(1f);
         }
     };
 
-    public static void setClipToRoundedOutline(View view, boolean clip) {
-        view.setOutlineProvider(clip ? sOutlineProvider : ViewOutlineProvider.BACKGROUND);
+    public static void setClipToRoundedOutline(View view, boolean clip, int roundedCornerRadius) {
+        if (clip) {
+            if (sRoundedRectProvider == null) {
+                sRoundedRectProvider = new SparseArray<ViewOutlineProvider>();
+            }
+            ViewOutlineProvider provider = sRoundedRectProvider.get(roundedCornerRadius);
+            if (provider == null) {
+                provider = new RoundedRectOutlineProvider(roundedCornerRadius);
+                if (sRoundedRectProvider.size() < MAX_CACHED_PROVIDER) {
+                    sRoundedRectProvider.put(roundedCornerRadius, provider);
+                }
+            }
+            view.setOutlineProvider(provider);
+        } else {
+            view.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
+        }
         view.setClipToOutline(clip);
     }
 }
diff --git a/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
index ab4d179..66f7687 100644
--- a/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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
@@ -13,20 +13,15 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.support.v17.leanback.R;
-import android.content.res.Resources;
-import android.graphics.Color;
 import android.graphics.Outline;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.view.ViewGroup;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 
 class ShadowHelperApi21 {
 
     static class ShadowImpl {
-        ViewGroup mShadowContainer;
+        View mShadowContainer;
         float mNormalZ;
         float mFocusedZ;
     }
@@ -41,9 +36,10 @@
 
     /* add shadows and return a implementation detail object */
     public static Object addDynamicShadow(
-            ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners) {
-        if (roundedCorners) {
-            RoundedRectHelperApi21.setClipToRoundedOutline(shadowContainer, true);
+            View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius) {
+        if (roundedCornerRadius > 0) {
+            RoundedRectHelperApi21.setClipToRoundedOutline(shadowContainer, true,
+                    roundedCornerRadius);
         } else {
             shadowContainer.setOutlineProvider(sOutlineProvider);
         }
@@ -52,7 +48,6 @@
         impl.mNormalZ = unfocusedZ;
         impl.mFocusedZ = focusedZ;
         shadowContainer.setZ(impl.mNormalZ);
-        shadowContainer.setTransitionGroup(true);
         return impl;
     }
 
diff --git a/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java b/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java
new file mode 100644
index 0000000..c4760d4
--- /dev/null
+++ b/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java
@@ -0,0 +1,35 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.support.v17.leanback.R;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+class ForegroundHelperApi23 {
+
+    public static Drawable getForeground(View view) {
+        return view.getForeground();
+    }
+
+    public static void setForeground(View view, Drawable drawable) {
+        view.setForeground(drawable);
+    }
+}
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index 8dc79e8..401a5c4 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -19,8 +19,8 @@
 
     sourceSets {
         main.manifest.srcFile 'AndroidManifest.xml'
-        main.java.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'src']
-        main.aidl.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'src']
+        main.java.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'api23', 'src']
+        main.aidl.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'api23', 'src']
         main.res.srcDirs = ['res']
 
         androidTest.setRoot('tests')
diff --git a/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java b/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java
index 80f05ed..6a4056e 100644
--- a/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java
+++ b/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java
@@ -19,10 +19,20 @@
  */
 public class TransitionListener {
 
+    protected Object mImpl;
+
     public void onTransitionStart(Object transition) {
     }
 
     public void onTransitionEnd(Object transition) {
     }
 
+    public void onTransitionCancel(Object transition) {
+    }
+
+    public void onTransitionPause(Object transition) {
+    }
+
+    public void onTransitionResume(Object transition) {
+    }
 }
diff --git a/v17/leanback/generatev4.py b/v17/leanback/generatev4.py
index 605e9a1..1b60b09e 100755
--- a/v17/leanback/generatev4.py
+++ b/v17/leanback/generatev4.py
@@ -20,7 +20,7 @@
 print "Generate v4 fragment related code for leanback"
 
 cls = ['Background', 'Base', 'BaseRow', 'Browse', 'Details', 'Error', 'Headers',
-      'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded']
+      'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded', 'GuidedStep']
 
 for w in cls:
     print "copy {}Fragment to {}SupportFragment".format(w, w)
@@ -31,10 +31,24 @@
     outfile.write("/* This file is auto-generated from {}Fragment.java.  DO NOT MODIFY. */\n\n".format(w))
 
     for line in file:
+        line = line.replace('IS_FRAMEWORK_FRAGMENT = true', 'IS_FRAMEWORK_FRAGMENT = false');
         for w in cls:
             line = line.replace('{}Fragment'.format(w), '{}SupportFragment'.format(w))
         line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
         line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+        line = line.replace('activity.getFragmentManager()', 'activity.getSupportFragmentManager()')
+        line = line.replace('Activity activity', 'FragmentActivity activity')
+        line = line.replace('(Activity', '(FragmentActivity')
         outfile.write(line)
     file.close()
     outfile.close()
+
+file = open('src/android/support/v17/leanback/app/PlaybackControlGlue.java', 'r')
+outfile = open('src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java', 'w')
+outfile.write("/* This file is auto-generated from PlaybackControlGlue.java.  DO NOT MODIFY. */\n\n")
+for line in file:
+    line = line.replace('PlaybackControlGlue', 'PlaybackControlSupportGlue');
+    line = line.replace('PlaybackOverlayFragment', 'PlaybackOverlaySupportFragment');
+    outfile.write(line)
+file.close()
+outfile.close()
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
index b4b6abe..221b84a 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
@@ -185,9 +185,12 @@
         ((Transition) transition).addTarget(targetView);
     }
 
-    static void setTransitionListener(Object transition, final TransitionListener listener) {
+    static void addTransitionListener(Object transition, final TransitionListener listener) {
+        if (listener == null) {
+            return;
+        }
         Transition t = (Transition) transition;
-        t.addListener(new Transition.TransitionListener() {
+        listener.mImpl = new Transition.TransitionListener() {
 
             @Override
             public void onTransitionStart(Transition transition) {
@@ -196,10 +199,12 @@
 
             @Override
             public void onTransitionResume(Transition transition) {
+                listener.onTransitionResume(transition);
             }
 
             @Override
             public void onTransitionPause(Transition transition) {
+                listener.onTransitionPause(transition);
             }
 
             @Override
@@ -209,8 +214,19 @@
 
             @Override
             public void onTransitionCancel(Transition transition) {
+                listener.onTransitionCancel(transition);
             }
-        });
+        };
+        t.addListener((Transition.TransitionListener) listener.mImpl);
+    }
+
+    static void removeTransitionListener(Object transition, final TransitionListener listener) {
+        if (listener == null || listener.mImpl == null) {
+            return;
+        }
+        Transition t = (Transition) transition;
+        t.removeListener((Transition.TransitionListener) listener.mImpl);
+        listener.mImpl = null;
     }
 
     static void runTransition(Object scene, Object transition) {
diff --git a/v17/leanback/project.properties b/v17/leanback/project.properties
index 91d2b02..b2ef7dc 100644
--- a/v17/leanback/project.properties
+++ b/v17/leanback/project.properties
@@ -11,5 +11,5 @@
 #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
 
 # Project target.
-target=android-19
+target=android-23
 android.library=true
diff --git a/v17/leanback/res/animator/lb_guidance_entry.xml b/v17/leanback/res/animator/lb_guidance_entry.xml
deleted file mode 100644
index e10d2ef..0000000
--- a/v17/leanback/res/animator/lb_guidance_entry.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="sequentially">
-
-    <set android:ordering="together">
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_delay"
-            android:propertyName="translationX"
-            android:valueFrom="@dimen/lb_guidance_entry_translationX"
-            android:valueTo="@dimen/lb_guidance_entry_translationX"
-            android:valueType="floatType" />
-
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_delay"
-            android:propertyName="alpha"
-            android:valueFrom="0.0"
-            android:valueTo="0.0"
-            android:valueType="floatType" />
-    </set>
-
-    <set android:ordering="together">
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_duration"
-            android:interpolator="@android:interpolator/decelerate_quad"
-            android:propertyName="translationX"
-            android:valueFrom="@dimen/lb_guidance_entry_translationX"
-            android:valueTo="0.0"
-            android:valueType="floatType" />
-
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_duration"
-            android:interpolator="@android:interpolator/decelerate_quad"
-            android:propertyName="alpha"
-            android:valueFrom="0.0"
-            android:valueTo="1.0"
-            android:valueType="floatType" />
-    </set>
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedactions_entry.xml b/v17/leanback/res/animator/lb_guidedactions_entry.xml
deleted file mode 100644
index ec6c655..0000000
--- a/v17/leanback/res/animator/lb_guidedactions_entry.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="sequentially">
-
-    <set android:ordering="together">
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_delay"
-            android:propertyName="translationX"
-            android:valueFrom="@dimen/lb_guidedactions_entry_translationX"
-            android:valueTo="@dimen/lb_guidedactions_entry_translationX"
-            android:valueType="floatType" />
-
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_delay"
-            android:propertyName="alpha"
-            android:valueFrom="0.0"
-            android:valueTo="0.0"
-            android:valueType="floatType" />
-    </set>
-
-    <set android:ordering="together">
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_duration"
-            android:interpolator="@android:interpolator/decelerate_quad"
-            android:propertyName="translationX"
-            android:valueFrom="@dimen/lb_guidedactions_entry_translationX"
-            android:valueTo="0.0"
-            android:valueType="floatType" />
-
-        <objectAnimator
-            android:duration="@integer/lb_guidedstep_entry_animation_duration"
-            android:interpolator="@android:interpolator/decelerate_quad"
-            android:propertyName="alpha"
-            android:valueFrom="0.0"
-            android:valueTo="1.0"
-            android:valueType="floatType" />
-    </set>
-</set>
\ No newline at end of file
diff --git a/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml b/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml
index f829eb3..e5dafb0 100644
--- a/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml
+++ b/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml
@@ -17,7 +17,6 @@
 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="@integer/lb_guidedactions_animation_duration"
     android:propertyName="alpha"
-    android:valueFrom="1.0"
     android:valueTo="0.0"
     android:interpolator="@animator/lb_decelerator_2"
     android:valueType="floatType" />
diff --git a/v17/leanback/res/animator/lb_guidedactions_selector_show.xml b/v17/leanback/res/animator/lb_guidedactions_selector_show.xml
index e8d69e5..fcfd9fa 100644
--- a/v17/leanback/res/animator/lb_guidedactions_selector_show.xml
+++ b/v17/leanback/res/animator/lb_guidedactions_selector_show.xml
@@ -20,7 +20,6 @@
     <objectAnimator
         android:duration="@integer/lb_guidedactions_animation_duration"
         android:propertyName="alpha"
-        android:valueFrom="0"
         android:valueTo="1.0"
         android:interpolator="@animator/lb_decelerator_2"
         android:valueType="floatType" />
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml b/v17/leanback/res/animator/lb_guidedstep_slide_down.xml
similarity index 82%
rename from v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml
rename to v17/leanback/res/animator/lb_guidedstep_slide_down.xml
index 86525c8..b31421f 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml
+++ b/v17/leanback/res/animator/lb_guidedstep_slide_down.xml
@@ -15,8 +15,8 @@
      limitations under the License.
 -->
 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="@integer/lb_guidedactions_item_animation_duration"
-    android:propertyName="alpha"
-    android:valueFrom="1.0"
+    android:duration="@android:integer/config_shortAnimTime"
+    android:propertyName="translationY"
+    android:valueFrom="@dimen/lb_guidedstep_slide_ime_distance"
     android:valueTo="0.0"
     android:valueType="floatType" />
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_end.xml b/v17/leanback/res/animator/lb_guidedstep_slide_in_from_end.xml
deleted file mode 100644
index 1dacdbc..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_end.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="together" >
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="translationX"
-        android:valueFrom="@dimen/lb_guidedstep_slide_end_distance"
-        android:valueTo="0.0"
-        android:valueType="floatType" />
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="alpha"
-        android:valueFrom="0.0"
-        android:valueTo="1.0"
-        android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_start.xml b/v17/leanback/res/animator/lb_guidedstep_slide_in_from_start.xml
deleted file mode 100644
index 3c01324..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_start.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="together" >
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="translationX"
-        android:valueFrom="@dimen/lb_guidedstep_slide_start_distance"
-        android:valueTo="0.0"
-        android:valueType="floatType" />
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="alpha"
-        android:valueFrom="0.0"
-        android:valueTo="1.0"
-        android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_end.xml b/v17/leanback/res/animator/lb_guidedstep_slide_out_to_end.xml
deleted file mode 100644
index 879a0cf..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_end.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="together" >
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="translationX"
-        android:valueFrom="0.0"
-        android:valueTo="@dimen/lb_guidedstep_slide_end_distance"
-        android:valueType="floatType" />
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.0"
-        android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_start.xml b/v17/leanback/res/animator/lb_guidedstep_slide_out_to_start.xml
deleted file mode 100644
index 4c9af82..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_start.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="together" >
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="translationX"
-        android:valueFrom="0.0"
-        android:valueTo="@dimen/lb_guidedstep_slide_start_distance"
-        android:valueType="floatType" />
-
-    <objectAnimator
-        android:duration="@android:integer/config_longAnimTime"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.0"
-        android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml b/v17/leanback/res/animator/lb_guidedstep_slide_up.xml
similarity index 83%
rename from v17/leanback/res/animator/lb_guidedactions_item_checked.xml
rename to v17/leanback/res/animator/lb_guidedstep_slide_up.xml
index 463b9f7..165fe18 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml
+++ b/v17/leanback/res/animator/lb_guidedstep_slide_up.xml
@@ -15,8 +15,8 @@
      limitations under the License.
 -->
 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="@integer/lb_guidedactions_item_animation_duration"
-    android:propertyName="alpha"
+    android:duration="@android:integer/config_shortAnimTime"
+    android:propertyName="translationY"
     android:valueFrom="0.0"
-    android:valueTo="1.0"
+    android:valueTo="@dimen/lb_guidedstep_slide_ime_distance"
     android:valueType="floatType" />
diff --git a/v17/leanback/res/drawable/lb_headers_right_fading.xml b/v17/leanback/res/drawable/lb_headers_right_fading.xml
index 96794db..b20c4e8 100644
--- a/v17/leanback/res/drawable/lb_headers_right_fading.xml
+++ b/v17/leanback/res/drawable/lb_headers_right_fading.xml
@@ -20,6 +20,6 @@
     <gradient
         android:angle="0"
         android:startColor="#00000000"
-        android:endColor="@color/lb_default_brand_color"
+        android:endColor="?attr/defaultBrandColor"
         />
 </shape>
diff --git a/v17/leanback/res/layout/lb_fullwidth_details_overview.xml b/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
index 8dbb630..415bd82 100644
--- a/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
+++ b/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
@@ -34,7 +34,7 @@
         android:layout_height="@dimen/lb_details_v2_card_height"
         android:layout_marginTop="@dimen/lb_details_v2_blank_height"
         android:clipToPadding="false"
-        android:foreground="#ffffff"
+        android:background="?attr/defaultBrandColor"
         android:elevation="@dimen/lb_details_overview_z"
         >
 
@@ -48,6 +48,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:id="@+id/details_overview_actions_background"
+            android:background="?attr/defaultBrandColorDark"
             android:orientation="vertical" >
 
             <android.support.v17.leanback.widget.HorizontalGridView
diff --git a/v17/leanback/res/layout/lb_guidedactions.xml b/v17/leanback/res/layout/lb_guidedactions.xml
index 43617c9..f2926d3 100644
--- a/v17/leanback/res/layout/lb_guidedactions.xml
+++ b/v17/leanback/res/layout/lb_guidedactions.xml
@@ -16,20 +16,36 @@
 -->
 <!-- Layout for the settings list fragment -->
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:id="@+id/guidedactions_root"
+    android:transitionName="guidedactions_root"
+    android:transitionGroup="false"
+    android:layout_width="0dp"
+    android:layout_weight="1"
+    android:layout_height="match_parent">
 
-    <RelativeLayout
-        style="?attr/guidedActionsContainerStyle" >
+    <android.support.v17.leanback.widget.NonOverlappingView
+        android:id="@+id/guidedactions_list_background"
+        android:transitionName="guidedactions_list_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        android:background="?attr/guidedActionsBackgroundDark" />
 
-        <FrameLayout
-            android:id="@+id/guidedactions_selector"
-            style="?attr/guidedActionsSelectorStyle" />
-
+    <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+        android:id="@+id/guidedactions_content"
+        android:transitionName="guidedactions_content"
+        android:transitionGroup="false"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
         <android.support.v17.leanback.widget.VerticalGridView
+            android:transitionGroup="true"
             android:id="@+id/guidedactions_list"
             style="?attr/guidedActionsListStyle" />
 
-    </RelativeLayout>
+        <android.support.v17.leanback.widget.NonOverlappingView
+            android:id="@+id/guidedactions_selector"
+            android:transitionName="guidedactions_selector"
+            style="?attr/guidedActionsSelectorStyle" />
+    </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
 
 </RelativeLayout>
diff --git a/v17/leanback/res/layout/lb_guidedactions_item.xml b/v17/leanback/res/layout/lb_guidedactions_item.xml
index 4e41454..831c355 100644
--- a/v17/leanback/res/layout/lb_guidedactions_item.xml
+++ b/v17/leanback/res/layout/lb_guidedactions_item.xml
@@ -20,7 +20,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     style="?attr/guidedActionItemContainerStyle" >
 
-    <ImageView
+    <android.support.v17.leanback.widget.CheckableImageView
         android:id="@+id/guidedactions_item_checkmark"
         style="?attr/guidedActionItemCheckmarkStyle"
         tools:ignore="ContentDescription" />
@@ -34,13 +34,14 @@
         android:id="@+id/guidedactions_item_content"
         style="?attr/guidedActionItemContentStyle" >
 
-        <TextView
+        <android.support.v17.leanback.widget.GuidedActionEditText
             android:id="@+id/guidedactions_item_title"
             style="?attr/guidedActionItemTitleStyle" />
 
-        <TextView
+        <android.support.v17.leanback.widget.GuidedActionEditText
             android:id="@+id/guidedactions_item_description"
             style="?attr/guidedActionItemDescriptionStyle" />
+
     </android.support.v17.leanback.widget.NonOverlappingLinearLayout>
 
     <ImageView
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml b/v17/leanback/res/layout/lb_guidedstep_background.xml
similarity index 65%
copy from v17/leanback/res/animator/lb_guidedactions_item_checked.xml
copy to v17/leanback/res/layout/lb_guidedstep_background.xml
index 463b9f7..08ea47d 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_background.xml
@@ -14,9 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="@integer/lb_guidedactions_item_animation_duration"
-    android:propertyName="alpha"
-    android:valueFrom="0.0"
-    android:valueTo="1.0"
-    android:valueType="floatType" />
+<android.support.v17.leanback.widget.NonOverlappingView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/guidedstep_background"
+    android:transitionName="guidedstep_background"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="?attr/guidedStepBackground" />
+
diff --git a/v17/leanback/res/layout/lb_guidedstep_fragment.xml b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
index 6e0b7ad..a41d47d 100644
--- a/v17/leanback/res/layout/lb_guidedstep_fragment.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
@@ -15,21 +15,57 @@
      limitations under the License.
 -->
 <!-- Layout for the frame of a 2 pane actions fragment. -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/content_frame"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/guidedstep_root"
+    android:orientation="horizontal"
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
+    <LinearLayout
+        android:id="@+id/content_frame"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
 
-    <FrameLayout
-        android:id="@+id/content_fragment"
-        android:layout_width="@dimen/lb_guidedstep_guidance_section_width"
-        android:layout_height="match_parent"
-        android:layout_alignParentStart="true" />
+        <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+            android:id="@+id/content_fragment"
+            android:layout_toStartOf="@+id/action_fragment"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="match_parent"
+            android:layout_alignParentStart="true" />
 
-    <FrameLayout
-        android:id="@+id/action_fragment"
-        android:layout_width="@dimen/lb_guidedactions_section_width_with_shadow"
-        android:layout_height="match_parent"
-        android:layout_alignParentEnd="true" />
+        <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+            android:id="@+id/action_fragment_root"
+            android:transitionName="action_fragment_root"
+            android:transitionGroup="false"
+            android:orientation="horizontal"
+            android:clipToPadding="false"
+            android:clipChildren="false"
+            android:paddingStart="@dimen/lb_guidedactions_section_shadow_width"
+            android:layout_width="0dp"
+            android:layout_weight="?attr/guidedActionContentWidthWeight"
+            android:layout_height="match_parent"
+            android:layout_alignParentEnd="true">
 
-</RelativeLayout>
\ No newline at end of file
+            <android.support.v17.leanback.widget.NonOverlappingView
+                android:id="@+id/action_fragment_background"
+                android:transitionName="action_fragment_background"
+                android:orientation="horizontal"
+                android:outlineProvider="paddedBounds"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="?attr/guidedActionsBackground"
+                android:elevation="?attr/guidedActionsElevation" />
+
+            <android.support.v17.leanback.widget.NonOverlappingLinearLayout
+                android:id="@+id/action_fragment"
+                android:transitionName="action_fragment"
+                android:transitionGroup="false"
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:elevation="?attr/guidedActionsElevation" />
+        </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
+
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_image_card_view.xml b/v17/leanback/res/layout/lb_image_card_view.xml
index 2261965..1bc23f8 100644
--- a/v17/leanback/res/layout/lb_image_card_view.xml
+++ b/v17/leanback/res/layout/lb_image_card_view.xml
@@ -15,59 +15,16 @@
      limitations under the License.
 -->
 
-<merge
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:lb="http://schemas.android.com/apk/res-auto">
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:lb="http://schemas.android.com/apk/res-auto" >
 
     <ImageView
         android:id="@+id/main_image"
-        lb:layout_viewType="main"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:scaleType="centerCrop"
-        android:adjustViewBounds="true"
-        android:contentDescription="@null" />
-        <android.support.v17.leanback.widget.NonOverlappingRelativeLayout
-            lb:layout_viewType="info"
-            android:id="@+id/info_field"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/lb_basic_card_info_height"
-            android:paddingStart="@dimen/lb_basic_card_info_padding_horizontal"
-            android:paddingEnd="@dimen/lb_basic_card_info_padding_horizontal"
-            android:paddingTop="@dimen/lb_basic_card_info_padding_top"
-            android:layout_centerHorizontal="true" >
-            <TextView
-                android:id="@+id/title_text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_alignParentStart="true"
-                android:layout_marginBottom="@dimen/lb_basic_card_info_text_margin"
-                android:maxLines="1"
-                android:fontFamily="sans-serif-condensed"
-                android:textColor="@color/lb_basic_card_title_text_color"
-                android:textSize="@dimen/lb_basic_card_title_text_size"
-                android:ellipsize="end" />
-            <TextView
-                android:id="@+id/content_text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/title_text"
-                android:layout_alignParentStart="true"
-                android:layout_toStartOf="@+id/extra_badge"
-                android:maxLines="1"
-                android:fontFamily="sans-serif-condensed"
-                android:textColor="@color/lb_basic_card_content_text_color"
-                android:textSize="@dimen/lb_basic_card_content_text_size"
-                android:ellipsize="none" />
-            <ImageView
-                android:id="@+id/extra_badge"
-                android:layout_width="@dimen/lb_basic_card_info_badge_size"
-                android:layout_height="@dimen/lb_basic_card_info_badge_size"
-                android:layout_marginStart="@dimen/lb_basic_card_info_badge_margin"
-                android:layout_alignBottom="@id/content_text"
-                android:layout_alignParentEnd="true"
-                android:scaleType="fitCenter"
-                android:visibility="gone"
-                android:contentDescription="@null" />
-        </android.support.v17.leanback.widget.NonOverlappingRelativeLayout>
-</merge>
+        style="?attr/lbImageCardViewImageStyle" />
+
+    <android.support.v17.leanback.widget.NonOverlappingRelativeLayout
+        android:id="@+id/info_field"
+        style="?attr/lbImageCardViewInfoAreaStyle">
+    </android.support.v17.leanback.widget.NonOverlappingRelativeLayout>
+
+</merge>
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_badge_left.xml
similarity index 68%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_badge_left.xml
index 45a40e1..35d2da6 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_badge_left.xml
@@ -15,7 +15,9 @@
      limitations under the License.
 -->
 
-<View
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent" />
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/extra_badge"
+    android:layout_alignBottom="@+id/content_text"
+    android:layout_alignParentStart="true"
+    android:layout_marginEnd="@dimen/lb_basic_card_info_badge_margin"
+    style="?attr/lbImageCardViewBadgeStyle" />
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_badge_right.xml
similarity index 68%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_badge_right.xml
index 45a40e1..02dd917 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_badge_right.xml
@@ -15,7 +15,9 @@
      limitations under the License.
 -->
 
-<View
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent" />
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/extra_badge"
+    android:layout_alignBottom="@+id/content_text"
+    android:layout_alignParentEnd="true"
+    android:layout_marginStart="@dimen/lb_basic_card_info_badge_margin"
+    style="?attr/lbImageCardViewBadgeStyle" />
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_content.xml
similarity index 80%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_content.xml
index 45a40e1..5592371 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_content.xml
@@ -15,7 +15,6 @@
      limitations under the License.
 -->
 
-<View
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content_text"
+    style="?attr/lbImageCardViewContentStyle" />
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_title.xml
similarity index 80%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_title.xml
index 45a40e1..67e2493 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_title.xml
@@ -15,7 +15,6 @@
      limitations under the License.
 -->
 
-<View
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/title_text"
+    style="?attr/lbImageCardViewTitleStyle" />
diff --git a/v17/leanback/res/layout/lb_search_fragment.xml b/v17/leanback/res/layout/lb_search_fragment.xml
index 57a46b4..25150d3 100644
--- a/v17/leanback/res/layout/lb_search_fragment.xml
+++ b/v17/leanback/res/layout/lb_search_fragment.xml
@@ -18,8 +18,6 @@
              android:id="@+id/lb_search_frame"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
-             android:paddingTop="@dimen/lb_search_bar_padding_top"
-             android:clipToPadding="false"
              android:clipChildren="false"
         >
         <FrameLayout
@@ -28,6 +26,7 @@
                 android:layout_height="match_parent"/>
     <android.support.v17.leanback.widget.SearchBar
             android:id="@+id/lb_search_bar"
+            android:layout_marginTop="@dimen/lb_search_bar_padding_top"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:clipChildren="false"
diff --git a/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml b/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml
index e26204b..9dd440b 100644
--- a/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml
@@ -23,6 +23,6 @@
   <slide
       android:duration="350"
       android:interpolator="@android:interpolator/linear_out_slow_in"
-      android:slideEdge="right">
+      android:slideEdge="@integer/slideEdgeEnd">
   </slide>
 </transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v21/lb_browse_return_transition.xml b/v17/leanback/res/transition-v21/lb_browse_return_transition.xml
index 84ae993..6d341b5 100644
--- a/v17/leanback/res/transition-v21/lb_browse_return_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_browse_return_transition.xml
@@ -18,7 +18,7 @@
   <slide
       android:interpolator="@android:interpolator/fast_out_linear_in"
       android:duration="350"
-      android:slideEdge="left">
+      android:slideEdge="@integer/slideEdgeStart">
       <targets>
           <target android:targetId="@id/browse_headers_root" />
           <target android:targetId="@id/title_orb" />
@@ -27,7 +27,7 @@
   <slide
       android:interpolator="@android:interpolator/fast_out_linear_in"
       android:duration="350"
-      android:slideEdge="right">
+      android:slideEdge="@integer/slideEdgeEnd">
       <targets>
           <target android:excludeId="@+id/browse_headers_root" />
           <target android:excludeId="@+id/title_orb" />
diff --git a/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml b/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
new file mode 100644
index 0000000..5ee74ee
--- /dev/null
+++ b/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" >
+  <fade
+      android:interpolator="@android:interpolator/fast_out_linear_in"
+      android:duration="@integer/lb_guidedstep_activity_background_fade_duration_ms">
+        <targets>
+            <target android:targetId="@id/guidedstep_background" />
+        </targets>
+  </fade>
+  <slide
+      android:interpolator="@android:interpolator/fast_out_linear_in"
+      android:duration="350"
+      android:slideEdge="@integer/slideEdgeStart">
+        <targets>
+            <target android:targetId="@id/guidance_icon" />
+            <target android:targetId="@id/guidance_title" />
+            <target android:targetId="@id/guidance_breadcrumb" />
+            <target android:targetId="@id/guidance_description" />
+        </targets>
+  </slide>
+  <slide
+      android:interpolator="@android:interpolator/fast_out_linear_in"
+      android:duration="350"
+      android:slideEdge="@integer/slideEdgeEnd">
+        <targets>
+            <target android:targetId="@id/action_fragment_background" />
+            <target android:targetId="@id/guidedactions_list_background" />
+            <target android:targetId="@id/guidedactions_content" />
+            <target android:targetId="@id/guidedactions_list" />
+            <target android:targetId="@id/guidedactions_selector" />
+            <target android:targetId="@id/guidedactions_list_background2" />
+            <target android:targetId="@id/guidedactions_content2" />
+            <target android:targetId="@id/guidedactions_list2" />
+            <target android:targetId="@id/guidedactions_selector2" />
+        </targets>
+  </slide>
+</transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml b/v17/leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml
similarity index 74%
copy from v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
copy to v17/leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml
index 2068c64..00466cb 100644
--- a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2014 The Android Open Source Project
+     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.
@@ -16,13 +16,7 @@
 -->
 
 <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" >
-  <changeBounds
-      android:duration="350"
-      android:interpolator="@android:interpolator/linear_out_slow_in">
-  </changeBounds>
-  <slide
-      android:duration="350"
+  <fade
       android:interpolator="@android:interpolator/linear_out_slow_in"
-      android:slideEdge="end">
-  </slide>
+      android:duration="150"/>
 </transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml b/v17/leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml
similarity index 78%
rename from v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
rename to v17/leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml
index 2068c64..ee06953 100644
--- a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2014 The Android Open Source Project
+     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.
@@ -16,13 +16,9 @@
 -->
 
 <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" >
-  <changeBounds
-      android:duration="350"
-      android:interpolator="@android:interpolator/linear_out_slow_in">
-  </changeBounds>
   <slide
       android:duration="350"
       android:interpolator="@android:interpolator/linear_out_slow_in"
-      android:slideEdge="end">
+      android:slideEdge="bottom">
   </slide>
 </transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v22/lb_browse_return_transition.xml b/v17/leanback/res/transition-v21/lb_vertical_grid_return_transition.xml
similarity index 64%
rename from v17/leanback/res/transition-v22/lb_browse_return_transition.xml
rename to v17/leanback/res/transition-v21/lb_vertical_grid_return_transition.xml
index e8dbee0..edb3816 100644
--- a/v17/leanback/res/transition-v22/lb_browse_return_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_vertical_grid_return_transition.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2014 The Android Open Source Project
+     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.
@@ -18,26 +18,15 @@
   <slide
       android:interpolator="@android:interpolator/fast_out_linear_in"
       android:duration="350"
-      android:slideEdge="start">
+      android:slideEdge="bottom">
       <targets>
-          <target android:targetId="@id/browse_headers_root" />
-          <target android:targetId="@id/title_orb" />
-      </targets>
-  </slide>
-  <slide
-      android:interpolator="@android:interpolator/fast_out_linear_in"
-      android:duration="350"
-      android:slideEdge="end">
-      <targets>
-          <target android:excludeId="@+id/browse_headers_root" />
           <target android:excludeId="@+id/title_orb" />
+          <target android:excludeId="@+id/title_text" />
+          <target android:excludeId="@+id/title_badge" />
       </targets>
   </slide>
   <fade
       android:interpolator="@android:interpolator/fast_out_linear_in"
       android:duration="350">
-      <targets>
-          <target android:excludeId="@+id/browse_headers_root" />
-      </targets>
   </fade>
 </transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/values-af/strings.xml b/v17/leanback/res/values-af/strings.xml
index c7109bb..0310403 100644
--- a/v17/leanback/res/values-af/strings.xml
+++ b/v17/leanback/res/values-af/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiveer hoë gehalte"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktiveer onderskrifte"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiveer onderskrifte"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooi"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Gaan voort"</string>
 </resources>
diff --git a/v17/leanback/res/values-am/strings.xml b/v17/leanback/res/values-am/strings.xml
index d5bf0f5..77d2993 100644
--- a/v17/leanback/res/values-am/strings.xml
+++ b/v17/leanback/res/values-am/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ከፍተኛ ጥራትን አሰናክል"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አንቃ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አሰናክል"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ጨርስ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ቀጥል"</string>
 </resources>
diff --git a/v17/leanback/res/values-ar/strings.xml b/v17/leanback/res/values-ar/strings.xml
index 31f4d1a..c52be7f 100644
--- a/v17/leanback/res/values-ar/strings.xml
+++ b/v17/leanback/res/values-ar/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"تعطيل الجودة العالية"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"تمكين الترجمة المصاحبة"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"تعطيل الترجمة المصاحبة"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"إنهاء"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"متابعة"</string>
 </resources>
diff --git a/v17/leanback/res/values-az-rAZ/strings.xml b/v17/leanback/res/values-az-rAZ/strings.xml
index d1e685f..cb558a0 100644
--- a/v17/leanback/res/values-az-rAZ/strings.xml
+++ b/v17/leanback/res/values-az-rAZ/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksək keyfiyyəti deaktiv edin"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Qapalı çəkilişi aktiv edin"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Qapalı çəkilişi deaktiv edin"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Bitir"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davam edin"</string>
 </resources>
diff --git a/v17/leanback/res/values-bg/strings.xml b/v17/leanback/res/values-bg/strings.xml
index 74c01b6..6b16775 100644
--- a/v17/leanback/res/values-bg/strings.xml
+++ b/v17/leanback/res/values-bg/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Деактивиране на високото качество"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Активиране на субтитрите"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Деактивиране на субтитрите"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Край"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Напред"</string>
 </resources>
diff --git a/v17/leanback/res/values-bn-rBD/strings.xml b/v17/leanback/res/values-bn-rBD/strings.xml
index 4f0526c..04669bd 100644
--- a/v17/leanback/res/values-bn-rBD/strings.xml
+++ b/v17/leanback/res/values-bn-rBD/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"উচ্চ গুণমান অক্ষম করুন"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"সাবটাইটেল সক্ষম করুন"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"সাবটাইটেল অক্ষম করুন"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"শেষ করুন"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"চালিয়ে যান"</string>
 </resources>
diff --git a/v17/leanback/res/values-ca/strings.xml b/v17/leanback/res/values-ca/strings.xml
index dbf20a8..6578f3b 100644
--- a/v17/leanback/res/values-ca/strings.xml
+++ b/v17/leanback/res/values-ca/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactiva l\'alta qualitat"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activa els subtítols tancats"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactiva els subtítols tancats"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalitza"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
 </resources>
diff --git a/v17/leanback/res/values-cs/strings.xml b/v17/leanback/res/values-cs/strings.xml
index 13f9689..8ffb4f3 100644
--- a/v17/leanback/res/values-cs/strings.xml
+++ b/v17/leanback/res/values-cs/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Vypnout vysokou kvalitu"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnout titulky"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnout titulky"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončit"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovat"</string>
 </resources>
diff --git a/v17/leanback/res/values-da/strings.xml b/v17/leanback/res/values-da/strings.xml
index 701138f..87c507b 100644
--- a/v17/leanback/res/values-da/strings.xml
+++ b/v17/leanback/res/values-da/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høj kvalitet"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér undertekster"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver undertekster"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Afslut"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsæt"</string>
 </resources>
diff --git a/v17/leanback/res/values-de/strings.xml b/v17/leanback/res/values-de/strings.xml
index db0c3e0..9d018c6 100644
--- a/v17/leanback/res/values-de/strings.xml
+++ b/v17/leanback/res/values-de/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hohe Qualität deaktivieren"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Untertitel aktivieren"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Untertitel deaktivieren"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fertigstellen"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Weiter"</string>
 </resources>
diff --git a/v17/leanback/res/values-el/strings.xml b/v17/leanback/res/values-el/strings.xml
index 6c4f603..310b6a9 100644
--- a/v17/leanback/res/values-el/strings.xml
+++ b/v17/leanback/res/values-el/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Απενεργοποίηση Υψηλής ποιότητας"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ενεργοποίηση υποτίτλων"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Απενεργοποίηση υποτίτλων"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Τέλος"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Συνέχεια"</string>
 </resources>
diff --git a/v17/leanback/res/values-en-rAU/strings.xml b/v17/leanback/res/values-en-rAU/strings.xml
index ed22ccd..0097135 100644
--- a/v17/leanback/res/values-en-rAU/strings.xml
+++ b/v17/leanback/res/values-en-rAU/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
 </resources>
diff --git a/v17/leanback/res/values-en-rGB/strings.xml b/v17/leanback/res/values-en-rGB/strings.xml
index ed22ccd..0097135 100644
--- a/v17/leanback/res/values-en-rGB/strings.xml
+++ b/v17/leanback/res/values-en-rGB/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
 </resources>
diff --git a/v17/leanback/res/values-en-rIN/strings.xml b/v17/leanback/res/values-en-rIN/strings.xml
index ed22ccd..0097135 100644
--- a/v17/leanback/res/values-en-rIN/strings.xml
+++ b/v17/leanback/res/values-en-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
 </resources>
diff --git a/v17/leanback/res/values-es-rUS/strings.xml b/v17/leanback/res/values-es-rUS/strings.xml
index ab05f83..8341a4d 100644
--- a/v17/leanback/res/values-es-rUS/strings.xml
+++ b/v17/leanback/res/values-es-rUS/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar calidad alta"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
 </resources>
diff --git a/v17/leanback/res/values-es/strings.xml b/v17/leanback/res/values-es/strings.xml
index 9e6c526..9f308c0 100644
--- a/v17/leanback/res/values-es/strings.xml
+++ b/v17/leanback/res/values-es/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar alta calidad"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
 </resources>
diff --git a/v17/leanback/res/values-et-rEE/strings.xml b/v17/leanback/res/values-et-rEE/strings.xml
index cfda00e..a97c385 100644
--- a/v17/leanback/res/values-et-rEE/strings.xml
+++ b/v17/leanback/res/values-et-rEE/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Keela kõrgkvaliteetne taasesitus"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Luba subtiitrid"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Keela subtiitrid"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Lõpeta"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jätka"</string>
 </resources>
diff --git a/v17/leanback/res/values-eu-rES/strings.xml b/v17/leanback/res/values-eu-rES/strings.xml
index d9f9bf7..c22f172 100644
--- a/v17/leanback/res/values-eu-rES/strings.xml
+++ b/v17/leanback/res/values-eu-rES/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desgaitu kalitate handiko erreprodukzioa"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Gaitu azpitituluak"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desgaitu azpitituluak"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Amaitu"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jarraitu"</string>
 </resources>
diff --git a/v17/leanback/res/values-fa/strings.xml b/v17/leanback/res/values-fa/strings.xml
index 0a2ceff..58e823f 100644
--- a/v17/leanback/res/values-fa/strings.xml
+++ b/v17/leanback/res/values-fa/strings.xml
@@ -25,7 +25,7 @@
     <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
     <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
     <string name="lb_playback_controls_play" msgid="731953341987346903">"پخش"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"مکث"</string>
+    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"توقف موقت"</string>
     <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"جلو بردن سریع"</string>
     <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"‏بازارسال سریع %1$dX"</string>
     <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"عقب بردن"</string>
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"غیرفعال کردن کیفیت بالا"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"فعال کردن زیرنویس"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"غیرفعال کردن زیرنویس"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"پایان"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ادامه"</string>
 </resources>
diff --git a/v17/leanback/res/values-fi/strings.xml b/v17/leanback/res/values-fi/strings.xml
index 92b5f12..0c55e6f 100644
--- a/v17/leanback/res/values-fi/strings.xml
+++ b/v17/leanback/res/values-fi/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Poista korkea laatu käytöstä"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ota tekstitys käyttöön"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Poista tekstitys käytöstä"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Valmis"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jatka"</string>
 </resources>
diff --git a/v17/leanback/res/values-fr-rCA/strings.xml b/v17/leanback/res/values-fr-rCA/strings.xml
index bbd3eea..b28beae 100644
--- a/v17/leanback/res/values-fr-rCA/strings.xml
+++ b/v17/leanback/res/values-fr-rCA/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la lecture haute qualité"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer le sous-titrage"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver le sous-titrage"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
 </resources>
diff --git a/v17/leanback/res/values-fr/strings.xml b/v17/leanback/res/values-fr/strings.xml
index 0a3e6fe..914bf08 100644
--- a/v17/leanback/res/values-fr/strings.xml
+++ b/v17/leanback/res/values-fr/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la haute qualité"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer les sous-titres"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver les sous-titres"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
 </resources>
diff --git a/v17/leanback/res/values-gl-rES/strings.xml b/v17/leanback/res/values-gl-rES/strings.xml
index 717b994..62b3a2b 100644
--- a/v17/leanback/res/values-gl-rES/strings.xml
+++ b/v17/leanback/res/values-gl-rES/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactivar alta calidade"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activar subtítulos"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactivar subtítulos"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
 </resources>
diff --git a/v17/leanback/res/values-gu-rIN/strings.xml b/v17/leanback/res/values-gu-rIN/strings.xml
index 2e4f30f..afec9da9 100644
--- a/v17/leanback/res/values-gu-rIN/strings.xml
+++ b/v17/leanback/res/values-gu-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ઉચ્ચ ગુણવત્તા અક્ષમ કરો"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ઉપશીર્ષક સક્ષમ કરો"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"વિગતવાર ઉપશીર્ષકોને અક્ષમ કરો"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"સમાપ્ત કરો"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ચાલુ રાખો"</string>
 </resources>
diff --git a/v17/leanback/res/values-hi/strings.xml b/v17/leanback/res/values-hi/strings.xml
index a926396..c243c17 100644
--- a/v17/leanback/res/values-hi/strings.xml
+++ b/v17/leanback/res/values-hi/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करें"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षक सक्षम करें"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षक अक्षम करें"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त करें"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"जारी रखें"</string>
 </resources>
diff --git a/v17/leanback/res/values-hr/strings.xml b/v17/leanback/res/values-hr/strings.xml
index 974de0a..bb6ebcc 100644
--- a/v17/leanback/res/values-hr/strings.xml
+++ b/v17/leanback/res/values-hr/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogući visoku kvalitetu"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogući titlove"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogući titlove"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Završi"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastavi"</string>
 </resources>
diff --git a/v17/leanback/res/values-hu/strings.xml b/v17/leanback/res/values-hu/strings.xml
index 427f1cd..cfeb2ad 100644
--- a/v17/leanback/res/values-hu/strings.xml
+++ b/v17/leanback/res/values-hu/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Jó minőségű lejátszás letiltása"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Feliratok engedélyezése"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Feliratok letiltása"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Befejezés"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Folytatás"</string>
 </resources>
diff --git a/v17/leanback/res/values-hy-rAM/strings.xml b/v17/leanback/res/values-hy-rAM/strings.xml
index 7e8112e..1ac5dd8 100644
--- a/v17/leanback/res/values-hy-rAM/strings.xml
+++ b/v17/leanback/res/values-hy-rAM/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Անջատել բարձր որակը"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Միացնել խորագրերը"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Անջատել խորագրերը"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Վերջ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Շարունակել"</string>
 </resources>
diff --git a/v17/leanback/res/values-in/strings.xml b/v17/leanback/res/values-in/strings.xml
index 2dca7d3..6569825 100644
--- a/v17/leanback/res/values-in/strings.xml
+++ b/v17/leanback/res/values-in/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Nonaktifkan Kualitas Tinggi"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktifkan Pembuatan Teks"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Nonaktifkan Pembuatan Teks"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Lanjutkan"</string>
 </resources>
diff --git a/v17/leanback/res/values-is-rIS/strings.xml b/v17/leanback/res/values-is-rIS/strings.xml
index c84a4c6..830b11e 100644
--- a/v17/leanback/res/values-is-rIS/strings.xml
+++ b/v17/leanback/res/values-is-rIS/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Slökkva á miklum gæðum"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Kveikja á skjátextum"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Slökkva á skjátextum"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Ljúka"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Halda áfram"</string>
 </resources>
diff --git a/v17/leanback/res/values-it/strings.xml b/v17/leanback/res/values-it/strings.xml
index 1b58e0c..2f0ca47 100644
--- a/v17/leanback/res/values-it/strings.xml
+++ b/v17/leanback/res/values-it/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disattiva alta qualità"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Attiva sottotitoli"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disattiva sottotitoli"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fine"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
 </resources>
diff --git a/v17/leanback/res/values-iw/strings.xml b/v17/leanback/res/values-iw/strings.xml
index f102498..f2bda58 100644
--- a/v17/leanback/res/values-iw/strings.xml
+++ b/v17/leanback/res/values-iw/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"השבת איכות גבוהה"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"הפעל כתוביות"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"השבת כתוביות"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"סיום"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"המשך"</string>
 </resources>
diff --git a/v17/leanback/res/values-ja/strings.xml b/v17/leanback/res/values-ja/strings.xml
index 802631c..09faa8b 100644
--- a/v17/leanback/res/values-ja/strings.xml
+++ b/v17/leanback/res/values-ja/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"高品質を無効にする"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"字幕を有効にする"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"字幕を無効にする"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完了"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"続行"</string>
 </resources>
diff --git a/v17/leanback/res/values-ka-rGE/strings.xml b/v17/leanback/res/values-ka-rGE/strings.xml
index 70aeada..ac9f4cd 100644
--- a/v17/leanback/res/values-ka-rGE/strings.xml
+++ b/v17/leanback/res/values-ka-rGE/strings.xml
@@ -50,4 +50,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"მაღალი ხარისხის გამორთვა"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"დახურული წარწერების ჩართვა"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"დახურული წარწერების გაუქმება"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"დასრულება"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"გაგრძელება"</string>
 </resources>
diff --git a/v17/leanback/res/values-kk-rKZ/strings.xml b/v17/leanback/res/values-kk-rKZ/strings.xml
index 9ed6ce2..380695b 100644
--- a/v17/leanback/res/values-kk-rKZ/strings.xml
+++ b/v17/leanback/res/values-kk-rKZ/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Жоғары сапаны өшіру"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жасырын титрлерді қосу"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жасырын титрлерді өшіру"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Аяқтау"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Жалғастыру"</string>
 </resources>
diff --git a/v17/leanback/res/values-km-rKH/strings.xml b/v17/leanback/res/values-km-rKH/strings.xml
index 7874af2..60f90e5 100644
--- a/v17/leanback/res/values-km-rKH/strings.xml
+++ b/v17/leanback/res/values-km-rKH/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"បិទ​គុណភាព​ខ្ពស់"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"បើក​ការ​ដាក់​ចំណង​ដែល​បាន​បិទ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"បិទ​ការ​ដាក់​ចំណង​ដែល​បាន​បិទ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"បញ្ចប់"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"បន្ត"</string>
 </resources>
diff --git a/v17/leanback/res/values-kn-rIN/strings.xml b/v17/leanback/res/values-kn-rIN/strings.xml
index 196b154..18206ed 100644
--- a/v17/leanback/res/values-kn-rIN/strings.xml
+++ b/v17/leanback/res/values-kn-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ಹೆಚ್ಚು ಗುಣಮಟ್ಟವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ಪೂರ್ಣಗೊಳಿಸು"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ಮುಂದುವರಿಸು"</string>
 </resources>
diff --git a/v17/leanback/res/values-ko/strings.xml b/v17/leanback/res/values-ko/strings.xml
index c244dbf..e262b1c 100644
--- a/v17/leanback/res/values-ko/strings.xml
+++ b/v17/leanback/res/values-ko/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"고화질 사용 중지"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"자막 사용 설정"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"자막 사용 중지"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"완료"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"계속"</string>
 </resources>
diff --git a/v17/leanback/res/values-ky-rKG/strings.xml b/v17/leanback/res/values-ky-rKG/strings.xml
index 4ddb284..74cc841 100644
--- a/v17/leanback/res/values-ky-rKG/strings.xml
+++ b/v17/leanback/res/values-ky-rKG/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Жогорку сапатты өчүрүү"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жабык субтитрлерди иштетүү"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жабык субтитрлерди өчүрүү"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Бүтүрүү"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Улантуу"</string>
 </resources>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v17/leanback/res/values-ldrtl/integers.xml
similarity index 72%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v17/leanback/res/values-ldrtl/integers.xml
index a4614f6..250523d 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v17/leanback/res/values-ldrtl/integers.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     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.
@@ -13,7 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<resources>
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_setting_light" />
-</selector>
+    <!-- Gravity.RIGHT -->
+    <integer name="slideEdgeStart">5</integer>
+    <!-- Gravity.LEFT -->
+    <integer name="slideEdgeEnd">3</integer>
+
+</resources>
\ No newline at end of file
diff --git a/v17/leanback/res/values-lo-rLA/strings.xml b/v17/leanback/res/values-lo-rLA/strings.xml
index 35f519b..d919e93 100644
--- a/v17/leanback/res/values-lo-rLA/strings.xml
+++ b/v17/leanback/res/values-lo-rLA/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"​ປິດ​ນຳ​ໃຊ້​ການຫຼິ້ນ​ດ້ວຍຄຸນ​ນະ​ພາບ​ສູງ"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"​ເປີດ​ນຳ​ໃຊ້​​ຄຳ​ບັນ​ຍາຍ​ແບບ​ປິດ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"​ປິດ​ນຳ​ໃຊ້​ຄຳ​ບັນ​ຍາຍ​ແບບ​ປິດ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ສໍາເລັດ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"​ສືບ​ຕໍ່"</string>
 </resources>
diff --git a/v17/leanback/res/values-lt/strings.xml b/v17/leanback/res/values-lt/strings.xml
index 6ca2bab..415fc25 100644
--- a/v17/leanback/res/values-lt/strings.xml
+++ b/v17/leanback/res/values-lt/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Išjungti aukštą kokybę"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Įgalinti subtitrus"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Išjungti subtitrus"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Baigti"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tęsti"</string>
 </resources>
diff --git a/v17/leanback/res/values-lv/strings.xml b/v17/leanback/res/values-lv/strings.xml
index 7d3bc2b..3979e43 100644
--- a/v17/leanback/res/values-lv/strings.xml
+++ b/v17/leanback/res/values-lv/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Atspējot augstas kvalitātes vienumu atskaņošanu"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Iespējot slēgtos parakstus"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Atspējot slēgtos parakstus"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Pabeigt"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Turpināt"</string>
 </resources>
diff --git a/v17/leanback/res/values-mk-rMK/strings.xml b/v17/leanback/res/values-mk-rMK/strings.xml
index 75666e0..ccf6d62 100644
--- a/v17/leanback/res/values-mk-rMK/strings.xml
+++ b/v17/leanback/res/values-mk-rMK/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Оневозможи висок квалитет"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Овозможи затворено објаснување"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Оневозможи затворено објаснување"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Заврши"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Продолжи"</string>
 </resources>
diff --git a/v17/leanback/res/values-ml-rIN/strings.xml b/v17/leanback/res/values-ml-rIN/strings.xml
index b900f09..356b0e9 100644
--- a/v17/leanback/res/values-ml-rIN/strings.xml
+++ b/v17/leanback/res/values-ml-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ഉയർന്ന നിലവാരം പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"പൂര്‍ത്തിയാക്കുക"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"തുടരുക"</string>
 </resources>
diff --git a/v17/leanback/res/values-mn-rMN/strings.xml b/v17/leanback/res/values-mn-rMN/strings.xml
index e4a8fcd..a7a640f 100644
--- a/v17/leanback/res/values-mn-rMN/strings.xml
+++ b/v17/leanback/res/values-mn-rMN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Өндөр чанарыг идэвхгүйжүүлэх"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Текст тайлбарыг идэвхжүүлэх"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Текст тайлбарыг идэвхгүйжүүлэх"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Дуусгах"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Үргэлжлүүлэх"</string>
 </resources>
diff --git a/v17/leanback/res/values-mr-rIN/strings.xml b/v17/leanback/res/values-mr-rIN/strings.xml
index 11748ec..b9b568a 100644
--- a/v17/leanback/res/values-mr-rIN/strings.xml
+++ b/v17/leanback/res/values-mr-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करा"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षके सक्षम करा"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षके अक्षम करा"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"सुरू ठेवा"</string>
 </resources>
diff --git a/v17/leanback/res/values-ms-rMY/strings.xml b/v17/leanback/res/values-ms-rMY/strings.xml
index c073e43..0a5f8bd 100644
--- a/v17/leanback/res/values-ms-rMY/strings.xml
+++ b/v17/leanback/res/values-ms-rMY/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Lumpuhkan Kualiti Tinggi"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Dayakan Kapsyen Tertutup"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Lumpuhkan Kapsyen Tertutup"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Teruskan"</string>
 </resources>
diff --git a/v17/leanback/res/values-my-rMM/strings.xml b/v17/leanback/res/values-my-rMM/strings.xml
index 2efaf7f..1b3cdee 100644
--- a/v17/leanback/res/values-my-rMM/strings.xml
+++ b/v17/leanback/res/values-my-rMM/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"အရည်အသွေးကောင်းအား ပိတ်ထားရန်"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"စာတမ်းထိုး ဖွင့်ရန်"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"စာတမ်းထိုးအား ပိတ်ထားရန်"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ပြီးပြီ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ဆက်လုပ်ရန်"</string>
 </resources>
diff --git a/v17/leanback/res/values-nb/strings.xml b/v17/leanback/res/values-nb/strings.xml
index f5ab2e1..c58544d 100644
--- a/v17/leanback/res/values-nb/strings.xml
+++ b/v17/leanback/res/values-nb/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høy kvalitet"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér teksting"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver teksting"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fullfør"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsett"</string>
 </resources>
diff --git a/v17/leanback/res/values-ne-rNP/strings.xml b/v17/leanback/res/values-ne-rNP/strings.xml
index c399985..54c92856 100644
--- a/v17/leanback/res/values-ne-rNP/strings.xml
+++ b/v17/leanback/res/values-ne-rNP/strings.xml
@@ -48,4 +48,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणस्तर असक्षम"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"बन्द क्याप्सनहरु सक्षम"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"बन्द क्याप्सनहरु असक्षम"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त गर्नुहोस्"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"जारी राख्नुहोस्"</string>
 </resources>
diff --git a/v17/leanback/res/values-nl/strings.xml b/v17/leanback/res/values-nl/strings.xml
index 1925e14..941aa79 100644
--- a/v17/leanback/res/values-nl/strings.xml
+++ b/v17/leanback/res/values-nl/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hoge kwaliteit uitschakelen"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ondertiteling inschakelen"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Ondertiteling uitschakelen"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooien"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Doorgaan"</string>
 </resources>
diff --git a/v17/leanback/res/values-pa-rIN/strings.xml b/v17/leanback/res/values-pa-rIN/strings.xml
index f9c7c4b..f197657 100644
--- a/v17/leanback/res/values-pa-rIN/strings.xml
+++ b/v17/leanback/res/values-pa-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ਉੱਚ ਗੁਣਵੱਤਾ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਸਮਰੱਥ ਬਣਾਓ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ਖ਼ਤਮ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ਜਾਰੀ ਰੱਖੋ"</string>
 </resources>
diff --git a/v17/leanback/res/values-pl/strings.xml b/v17/leanback/res/values-pl/strings.xml
index 18b8bf6..7598c73 100644
--- a/v17/leanback/res/values-pl/strings.xml
+++ b/v17/leanback/res/values-pl/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Wyłącz wysoką jakość"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Włącz napisy"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Wyłącz napisy"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Zakończ"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Dalej"</string>
 </resources>
diff --git a/v17/leanback/res/values-pt-rBR/strings.xml b/v17/leanback/res/values-pt-rBR/strings.xml
index 79b9d40..12c9533 100644
--- a/v17/leanback/res/values-pt-rBR/strings.xml
+++ b/v17/leanback/res/values-pt-rBR/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
 </resources>
diff --git a/v17/leanback/res/values-pt-rPT/strings.xml b/v17/leanback/res/values-pt-rPT/strings.xml
index f269712..7b12f5e 100644
--- a/v17/leanback/res/values-pt-rPT/strings.xml
+++ b/v17/leanback/res/values-pt-rPT/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar legendas"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar legendas"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
 </resources>
diff --git a/v17/leanback/res/values-pt/strings.xml b/v17/leanback/res/values-pt/strings.xml
index 79b9d40..12c9533 100644
--- a/v17/leanback/res/values-pt/strings.xml
+++ b/v17/leanback/res/values-pt/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
 </resources>
diff --git a/v17/leanback/res/values-ro/strings.xml b/v17/leanback/res/values-ro/strings.xml
index cb6aa4a..b4f9ee3 100644
--- a/v17/leanback/res/values-ro/strings.xml
+++ b/v17/leanback/res/values-ro/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Dezactivează calitatea înaltă"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activează subtitrările"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Dezactivează subtitrările"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizați"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuați"</string>
 </resources>
diff --git a/v17/leanback/res/values-ru/strings.xml b/v17/leanback/res/values-ru/strings.xml
index fdb453b..864054a 100644
--- a/v17/leanback/res/values-ru/strings.xml
+++ b/v17/leanback/res/values-ru/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Отключить высокое качество."</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Включить субтитры."</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Отключить субтитры."</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Готово"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Далее"</string>
 </resources>
diff --git a/v17/leanback/res/values-si-rLK/strings.xml b/v17/leanback/res/values-si-rLK/strings.xml
index e5c0cf4..3db1293 100644
--- a/v17/leanback/res/values-si-rLK/strings.xml
+++ b/v17/leanback/res/values-si-rLK/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"උපරිම ගුණත්වය අබල කරන ලදි"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"වැසුණු ශිර්ෂ කිරීම සබල කරන ලදි"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"වැසුණු ශිර්ෂ කිරීම අබල කරන ලදි"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"අවසානය"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"දිගටම කර ගෙන යන්න"</string>
 </resources>
diff --git a/v17/leanback/res/values-sk/strings.xml b/v17/leanback/res/values-sk/strings.xml
index 74a9044..a317d18 100644
--- a/v17/leanback/res/values-sk/strings.xml
+++ b/v17/leanback/res/values-sk/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zakázať médiá vo vysokej kvalite"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnúť skryté titulky"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnúť skryté titulky"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončiť"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovať"</string>
 </resources>
diff --git a/v17/leanback/res/values-sl/strings.xml b/v17/leanback/res/values-sl/strings.xml
index b5d0e1d..7b16952 100644
--- a/v17/leanback/res/values-sl/strings.xml
+++ b/v17/leanback/res/values-sl/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogoči visoko kakovost"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogoči podnapise"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogoči podnapise"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončaj"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Naprej"</string>
 </resources>
diff --git a/v17/leanback/res/values-sq-rAL/strings.xml b/v17/leanback/res/values-sq-rAL/strings.xml
index 28c313f..723b90c 100644
--- a/v17/leanback/res/values-sq-rAL/strings.xml
+++ b/v17/leanback/res/values-sq-rAL/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Çaktivizo \"Cilësinë e lartë\""</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivizo titrat"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Çaktivizo titrat me sekuencë kohore"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Përfundo"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Vazhdo"</string>
 </resources>
diff --git a/v17/leanback/res/values-sr/strings.xml b/v17/leanback/res/values-sr/strings.xml
index bb5c32d..df6c6b1 100644
--- a/v17/leanback/res/values-sr/strings.xml
+++ b/v17/leanback/res/values-sr/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Онемогући висок квалитет"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Омогући титлове"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Онемогући титлове"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Доврши"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Настави"</string>
 </resources>
diff --git a/v17/leanback/res/values-sv/strings.xml b/v17/leanback/res/values-sv/strings.xml
index 1a8e757..9b874ca 100644
--- a/v17/leanback/res/values-sv/strings.xml
+++ b/v17/leanback/res/values-sv/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inaktivera hög kvalitet"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivera textning"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inaktivera textning"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Slutför"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsätt"</string>
 </resources>
diff --git a/v17/leanback/res/values-sw/strings.xml b/v17/leanback/res/values-sw/strings.xml
index 0ad04d1..53ef95a 100644
--- a/v17/leanback/res/values-sw/strings.xml
+++ b/v17/leanback/res/values-sw/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zima Ubora wa Juu"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Washa manukuu"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Zima manukuu"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Kamilisha"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Endelea"</string>
 </resources>
diff --git a/v17/leanback/res/values-ta-rIN/strings.xml b/v17/leanback/res/values-ta-rIN/strings.xml
index f67ee4d..1cc2eea 100644
--- a/v17/leanback/res/values-ta-rIN/strings.xml
+++ b/v17/leanback/res/values-ta-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"உயர் தரத்தை முடக்கு"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"விரிவான வசனங்களை இயக்கு"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"விரிவான வசனங்களை முடக்கு"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"முடி"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"தொடர்க"</string>
 </resources>
diff --git a/v17/leanback/res/values-te-rIN/strings.xml b/v17/leanback/res/values-te-rIN/strings.xml
index f71e8cb..32d311d 100644
--- a/v17/leanback/res/values-te-rIN/strings.xml
+++ b/v17/leanback/res/values-te-rIN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"అధిక నాణ్యతను నిలిపివేయి"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"సంవృత శీర్షికలను ప్రారంభించు"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"సంవృత శీర్షికలను నిలిపివేయి"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ముగించు"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"కొనసాగించు"</string>
 </resources>
diff --git a/v17/leanback/res/values-th/strings.xml b/v17/leanback/res/values-th/strings.xml
index 093a529..d3eb2a3 100644
--- a/v17/leanback/res/values-th/strings.xml
+++ b/v17/leanback/res/values-th/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ปิดใช้คุณภาพสูง"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"เปิดใช้คำบรรยาย"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ปิดใช้คำบรรยาย"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"เสร็จสิ้น"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ต่อไป"</string>
 </resources>
diff --git a/v17/leanback/res/values-tl/strings.xml b/v17/leanback/res/values-tl/strings.xml
index a536298..f50b4d1 100644
--- a/v17/leanback/res/values-tl/strings.xml
+++ b/v17/leanback/res/values-tl/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"I-disable ang Mataas na Kalidad"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"I-enable ang Paglalagay ng Subtitle"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"I-disable ang Paglalagay ng Subtitle"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tapusin"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Magpatuloy"</string>
 </resources>
diff --git a/v17/leanback/res/values-tr/strings.xml b/v17/leanback/res/values-tr/strings.xml
index 800436c..814cb29 100644
--- a/v17/leanback/res/values-tr/strings.xml
+++ b/v17/leanback/res/values-tr/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksek Kalitede Oynatmayı Devre Dışı Bırak"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Altyazıları Etkinleştir"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Altyazıları Devre Dışı Bırak"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Son"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Devam"</string>
 </resources>
diff --git a/v17/leanback/res/values-uk/strings.xml b/v17/leanback/res/values-uk/strings.xml
index 79b2782..a38db30 100644
--- a/v17/leanback/res/values-uk/strings.xml
+++ b/v17/leanback/res/values-uk/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Вимкнути високу якість"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Увімкнути субтитри"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Вимкнути субтитри"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Закінчити"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Продовжити"</string>
 </resources>
diff --git a/v17/leanback/res/values-ur-rPK/strings.xml b/v17/leanback/res/values-ur-rPK/strings.xml
index b670251..666cf71 100644
--- a/v17/leanback/res/values-ur-rPK/strings.xml
+++ b/v17/leanback/res/values-ur-rPK/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"اعلی معیار کو غیر فعال کریں"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"سب ٹائٹلز کو فعال کریں"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"سب ٹائٹلز کو غیر فعال کریں"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"مکمل کریں"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"جاری رکھیں"</string>
 </resources>
diff --git a/v17/leanback/res/values-uz-rUZ/strings.xml b/v17/leanback/res/values-uz-rUZ/strings.xml
index c761244..d81d8de 100644
--- a/v17/leanback/res/values-uz-rUZ/strings.xml
+++ b/v17/leanback/res/values-uz-rUZ/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yuqori sifatni o‘chirib qo‘yish"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Taglavhalarni yoqish"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Taglavhalarni o‘chirib qo‘yish"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tugatish"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davom etish"</string>
 </resources>
diff --git a/v17/leanback/res/values-v19/themes.xml b/v17/leanback/res/values-v19/themes.xml
index 53befec..74e0e2e9 100644
--- a/v17/leanback/res/values-v19/themes.xml
+++ b/v17/leanback/res/values-v19/themes.xml
@@ -20,6 +20,7 @@
         <item name="playbackProgressPrimaryColor">@color/lb_playback_progress_color_no_theme</item>
         <item name="playbackControlsIconHighlightColor">@color/lb_playback_icon_highlight_no_theme</item>
         <item name="defaultBrandColor">@color/lb_default_brand_color</item>
+        <item name="defaultBrandColorDark">@color/lb_default_brand_color_dark</item>
 
         <item name="android:windowOverscan">true</item>
         <item name="guidedStepTheme">@style/Theme.Leanback.GuidedStep</item>
diff --git a/v17/leanback/res/values-v21/themes.xml b/v17/leanback/res/values-v21/themes.xml
index 3b48dae..1072b2b 100644
--- a/v17/leanback/res/values-v21/themes.xml
+++ b/v17/leanback/res/values-v21/themes.xml
@@ -21,6 +21,8 @@
         <item name="playbackControlsIconHighlightColor">?android:attr/colorAccent</item>
         <item name="defaultBrandColor">?android:attr/colorPrimary</item>
         <item name="android:colorPrimary">@color/lb_default_brand_color</item>
+        <item name="defaultBrandColorDark">?android:attr/colorPrimaryDark</item>
+        <item name="android:colorPrimaryDark">@color/lb_default_brand_color_dark</item>
 
         <item name="android:windowOverscan">true</item>
         <item name="guidedStepTheme">@style/Theme.Leanback.GuidedStep</item>
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/values-v22/integers.xml
similarity index 71%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/values-v22/integers.xml
index 45a40e1..fdd7792 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/values-v22/integers.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2014 The Android Open Source Project
+     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.
@@ -14,8 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<resources>
 
-<View
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent" />
+    <!-- Gravity.START -->
+    <integer name="slideEdgeStart">0x800003</integer>
+    <!-- Gravity.END -->
+    <integer name="slideEdgeEnd">0x800005</integer>
+
+</resources>
\ No newline at end of file
diff --git a/v17/leanback/res/values-vi/strings.xml b/v17/leanback/res/values-vi/strings.xml
index baf1c44..881734b 100644
--- a/v17/leanback/res/values-vi/strings.xml
+++ b/v17/leanback/res/values-vi/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Tắt chế độ chất lượng cao"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Bật phụ đề"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Tắt phụ đề"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Hoàn tất"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tiếp tục"</string>
 </resources>
diff --git a/v17/leanback/res/values-zh-rCN/strings.xml b/v17/leanback/res/values-zh-rCN/strings.xml
index 17c52b6..fc3fa10 100644
--- a/v17/leanback/res/values-zh-rCN/strings.xml
+++ b/v17/leanback/res/values-zh-rCN/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"关闭高画质模式"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"开启字幕"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"关闭字幕"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"继续"</string>
 </resources>
diff --git a/v17/leanback/res/values-zh-rHK/strings.xml b/v17/leanback/res/values-zh-rHK/strings.xml
index 5e87989..7cba4b5 100644
--- a/v17/leanback/res/values-zh-rHK/strings.xml
+++ b/v17/leanback/res/values-zh-rHK/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"停用高畫質"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"繼續"</string>
 </resources>
diff --git a/v17/leanback/res/values-zh-rTW/strings.xml b/v17/leanback/res/values-zh-rTW/strings.xml
index 67efc40..dcca2db 100644
--- a/v17/leanback/res/values-zh-rTW/strings.xml
+++ b/v17/leanback/res/values-zh-rTW/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"停用高品質播放"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"繼續"</string>
 </resources>
diff --git a/v17/leanback/res/values-zu/strings.xml b/v17/leanback/res/values-zu/strings.xml
index f17455d..f4c589d 100644
--- a/v17/leanback/res/values-zu/strings.xml
+++ b/v17/leanback/res/values-zu/strings.xml
@@ -46,4 +46,6 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Khubaza ikhwalithi ephezulu"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Nika amandla imibhalo engezansi"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Khubaza imihbalo engezansi"</string>
+    <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Qeda"</string>
+    <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Qhubeka"</string>
 </resources>
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index e7da321..90f010a 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -49,6 +49,10 @@
     </declare-styleable>
 
     <declare-styleable name="lbBaseCardView">
+        <!-- Defines the background of card -->
+        <attr name="cardForeground" format="reference|color"/>
+        <!-- Defines the background of card -->
+        <attr name="cardBackground" format="reference|color"/>
         <!-- Defines the type of the card layout -->
         <attr name="cardType" format="enum">
             <!-- A simple card layout with a single layout region. -->
@@ -116,7 +120,23 @@
     </declare-styleable>
 
     <declare-styleable name="lbImageCardView">
+        <!-- Deprecated. Use 'lbImageCardViewInfoAreaStyle' instead. -->
         <attr name="infoAreaBackground" format="reference|color"/>
+        <!-- Use these attributes to override a ImageCardView's component style. -->
+        <attr name="lbImageCardViewImageStyle" format="reference" />
+        <attr name="lbImageCardViewTitleStyle" format="reference" />
+        <attr name="lbImageCardViewContentStyle" format="reference" />
+        <attr name="lbImageCardViewBadgeStyle" format="reference" />
+        <attr name="lbImageCardViewInfoAreaStyle" format="reference" />
+        <!-- Defines what components the ImageCardView will use. -->
+        <attr name="lbImageCardViewType">
+            <flag name="Title" value="1" />
+            <flag name="Content" value="2" />
+            <flag name="IconOnRight" value="4" />
+            <flag name="IconOnLeft" value="8" />
+            <!-- Only display the main image. -->
+            <flag name="ImageOnly" value="0" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="lbSearchOrbView">
@@ -258,6 +278,12 @@
              b) SDK < 21: set the brand color explicitly via defaultBrandColor, or programatically.
          -->
         <attr name="defaultBrandColor" format="reference|color" />
+        <!-- Default dark brand color used for the background of certain leanback visual elements
+             such as the actions background. If your app runs on:
+             a) SDK 21+: set colorPrimaryDark, used by the leanback launcher and elsewhere, and defaultBrandColorDark will inherit it.
+             b) SDK < 21: set the brand color explicitly via defaultBrandColorDark, or programatically.
+         -->
+        <attr name="defaultBrandColorDark" format="reference|color" />
 
         <!-- Default colors -->
         <attr name="defaultSearchColor" format="reference|color" />
@@ -292,27 +318,18 @@
              Theme attribute used to inspect theme inheritance. -->
         <attr name="guidedStepThemeFlag" format="boolean" />
 
-        <!-- Theme attribute for the animation used when a guided step element is animated in on
-             fragment stack push. Default is {@link
-             android.support.v17.leanback.R.animator#lb_guidedstep_slide_in_from_end}. -->
-        <attr name="guidedStepEntryAnimation" format="reference" />
-        <!-- Theme attribute for the animation used when a guided step element is animated out on
-             fragment stack push. Default is {@link
-             android.support.v17.leanback.R.animator#lb_guidedstep_slide_out_to_start}. -->
-        <attr name="guidedStepExitAnimation" format="reference" />
-        <!-- Theme attribute for the animation used when a guided step element is animated in on
-             fragment stack pop. Default is {@link
-             android.support.v17.leanback.R.animator#lb_guidedstep_slide_in_from_start}. -->
-        <attr name="guidedStepReentryAnimation" format="reference" />
-        <!-- Theme attribute for the animation used when a guided step element is animated out on
-             fragment stack pop. Default is {@link
-             android.support.v17.leanback.R.animator#lb_guidedstep_slide_out_to_end}. -->
-        <attr name="guidedStepReturnAnimation" format="reference" />
+        <!-- Theme attribute of background drawable used by GuidedStepFragment. -->
+        <attr name="guidedStepBackground" format="reference|color" />
 
-        <!-- Theme attribute for the animation used when the guidance is animated in at activity
-             start. Default is {@link android.support.v17.leanback.R.animator#lb_guidance_entry}.
-             -->
-        <attr name="guidanceEntryAnimation" format="reference" />
+        <!-- Theme attribute for the animation used when a guided step element is animated in
+             response to the IME appearing. Default is {@link
+             android.support.v17.leanback.R.animator#lb_guidedstep_slide_up}. -->
+        <attr name="guidedStepImeAppearingAnimation" format="reference" />
+        <!-- Theme attribute for the animation used when a guided step element is animated in
+             response to the IME disappearing. Default is {@link
+             android.support.v17.leanback.R.animator#lb_guidedstep_slide_down}. -->
+        <attr name="guidedStepImeDisappearingAnimation" format="reference" />
+
         <!-- Theme attribute for the style of the main container in a GuidanceStylist. Default is
              {@link android.support.v17.leanback.R.style#Widget_Leanback_GuidanceContainerStyle}.-->
         <attr name="guidanceContainerStyle" format="reference" />
@@ -329,10 +346,6 @@
              {@link android.support.v17.leanback.R.style#Widget_Leanback_GuidanceIconStyle}. -->
         <attr name="guidanceIconStyle" format="reference" />
 
-        <!-- Theme attribute for the animation used in a GuidedActionsPresenter when the actions
-             list is animated in at activity start. Default is {@link
-             android.support.v17.leanback.R.animator#lb_guidedactions_entry}. -->
-        <attr name="guidedActionsEntryAnimation" format="reference" />
         <!-- Theme attribute for the animation used in a GuidedActionsPresenter when the action
              selector is animated in at activity start. Default is {@link
              android.support.v17.leanback.R.animator#lb_guidedactions_selector_show}. -->
@@ -341,12 +354,22 @@
              selector is animated in at activity start. Default is {@link
              android.support.v17.leanback.R.animator#lb_guidedactions_selector_hide}. -->
         <attr name="guidedActionsSelectorHideAnimation" format="reference" />
-        <!-- Theme attribute for the style of the container in a GuidedActionsPresenter. Default is
-             {@link android.support.v17.leanback.R.style#Widget_Leanback_GuidedActionsContainerStyle}. -->
-        <attr name="guidedActionsContainerStyle" format="reference" />
         <!-- Theme attribute for the style of the item selector in a GuidedActionsPresenter. Default is
              {@link android.support.v17.leanback.R.style#Widget_Leanback_GuidedActionsSelectorStyle}. -->
         <attr name="guidedActionsSelectorStyle" format="reference" />
+
+        <!-- Theme attribute for the shadow elevation of GuidedActions. Default is
+             {@link android.support.v17.leanback.R.dimen#lb_guidedactions_elevation}.-->
+        <attr name="guidedActionsElevation" format="dimension|reference" />
+
+        <!-- Theme attribute for the background of GuidedActions. Default is
+             {@link android.support.v17.leanback.R.color#lb_guidedactions_background}.-->
+        <attr name="guidedActionsBackground" format="reference" />
+
+        <!-- Theme attribute for the dark version background of GuidedActions. Default is
+             {@link android.support.v17.leanback.R.color#lb_guidedactions_background_dark}.-->
+        <attr name="guidedActionsBackgroundDark" format="reference" />
+
         <!-- Theme attribute for the style of the list in a GuidedActionsPresenter. Default is
              {@link android.support.v17.leanback.R.style#Widget_Leanback_GuidedActionsListStyle}.-->
         <attr name="guidedActionsListStyle" format="reference" />
@@ -381,14 +404,6 @@
         <attr name="guidedActionItemChevronStyle" format="reference" />
 
         <!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
-             is checked. Default is {@link
-             android.support.v17.leanback.R.animator#lb_guidedactions_item_checked}. -->
-        <attr name="guidedActionCheckedAnimation" format="reference" />
-        <!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
-             is unchecked. Default is {@link
-             android.support.v17.leanback.R.animator#lb_guidedactions_item_unchecked}. -->
-        <attr name="guidedActionUncheckedAnimation" format="reference" />
-        <!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
              is pressed. Default is {@link
              android.support.v17.leanback.R.animator#lb_guidedactions_item_pressed}. -->
         <attr name="guidedActionPressedAnimation" format="reference" />
@@ -404,14 +419,12 @@
              decoration when its action is disabled. Default is {@link
              android.support.v17.leanback.R.string#lb_guidedactions_item_disabled_chevron_alpha}. -->
         <attr name="guidedActionDisabledChevronAlpha" format="reference" />
-        <!-- Theme attribute used in a GuidedActionsPresenter for the width of the text area of
-             a single action when there is an icon present. Default is {@link
-             android.support.v17.leanback.R.dimen#lb_guidedactions_item_text_width}. -->
-        <attr name="guidedActionContentWidth" format="reference" />
-        <!-- Theme attribute used in a GuidedActionsPresenter for the width of the text area of
-             a single action when there is no icon present. Default is {@link
-             android.support.v17.leanback.R.dimen#lb_guidedactions_item_text_width_no_icon}. -->
-        <attr name="guidedActionContentWidthNoIcon" format="reference" />
+        <!-- Theme attribute used for the weight of actions.  Default is {@link
+             android.support.v17.leanback.R.string#lb_guidedactions_width_weight}. -->
+        <attr name="guidedActionContentWidthWeight" format="reference" />
+        <!-- Theme attribute used for the weight of actions when there are two panels.  Default is {@link
+             android.support.v17.leanback.R.string#lb_guidedactions_width_weight_two_panels}. -->
+        <attr name="guidedActionContentWidthWeightTwoPanels" format="reference" />
         <!-- Theme attribute used in a GuidedActionsPresenter for the max lines of the title text
              view when the action's isMultilineDescription is set to false. Default is {@link
              android.support.v17.leanback.R.integer#lb_guidedactions_item_title_min_lines}. -->
@@ -431,4 +444,4 @@
 
     </declare-styleable>
 
-</resources>
+</resources>
\ No newline at end of file
diff --git a/v17/leanback/res/values/colors.xml b/v17/leanback/res/values/colors.xml
index e63c58b..858ace5 100644
--- a/v17/leanback/res/values/colors.xml
+++ b/v17/leanback/res/values/colors.xml
@@ -52,6 +52,7 @@
     <color name="lb_basic_card_content_text_color">#B3EEEEEE</color>
 
     <color name="lb_default_brand_color">#FF455A64</color>
+    <color name="lb_default_brand_color_dark">#FF222D32</color>
     <color name="lb_default_search_color">#FFFFAA3F</color>
 
     <color name="lb_control_button_color">#66EEEEEE</color>
@@ -71,6 +72,7 @@
 
     <!-- refactor naming here -->
     <color name="lb_guidedactions_background">#FF111111</color>
+    <color name="lb_guidedactions_background_dark">#FF080808</color>
     <color name="lb_guidedactions_selector_color">#26FFFFFF</color>
     <color name="lb_guidedactions_item_unselected_text_color">#FFF1F1F1</color>
     <!-- end refactor naming -->
diff --git a/v17/leanback/res/values/dimens.xml b/v17/leanback/res/values/dimens.xml
index 275612e..053c7e0 100644
--- a/v17/leanback/res/values/dimens.xml
+++ b/v17/leanback/res/values/dimens.xml
@@ -180,7 +180,7 @@
 
 
     <!-- Search Fragment -->
-    <dimen name="lb_search_browse_rows_align_top">120dp</dimen>
+    <dimen name="lb_search_browse_rows_align_top">147dp</dimen>
     <dimen name="lb_search_browse_row_padding_start">56dp</dimen>
 
     <dimen name="lb_search_orb_size">52dp</dimen>
@@ -203,6 +203,7 @@
     <dimen name="lb_basic_card_info_height">52dp</dimen>
     <dimen name="lb_basic_card_info_height_no_content">34dp</dimen>
     <dimen name="lb_basic_card_info_padding_top">7dp</dimen>
+    <dimen name="lb_basic_card_info_padding_bottom">8dp</dimen>
     <dimen name="lb_basic_card_info_padding_horizontal">11dp</dimen>
     <dimen name="lb_basic_card_info_text_margin">1dp</dimen>
     <dimen name="lb_basic_card_title_text_size">14sp</dimen>
@@ -223,19 +224,22 @@
     <dimen name="lb_rounded_rect_corner_radius">2dp</dimen>
 
     <!-- GuidedStepFragment -->
-    <dimen name="lb_guidedstep_guidance_section_width">576dp</dimen>
     <dimen name="lb_guidedstep_slide_start_distance">-200dp</dimen>
     <dimen name="lb_guidedstep_slide_end_distance">200dp</dimen>
+    <dimen name="lb_guidedstep_slide_ime_distance">-100dp</dimen>
 
     <dimen name="lb_guidance_entry_translationX">-120dp</dimen>
 
     <dimen name="lb_guidedactions_entry_translationX">384dp</dimen>
-    <dimen name="lb_guidedactions_section_width">384dp</dimen>
-    <dimen name="lb_guidedactions_section_width_with_shadow">400dp</dimen>
+    <item name="lb_guidedactions_width_weight" format="float" type="string">0.666666667</item>
+    <item name="lb_guidedactions_width_weight_two_panels" format="float" type="string">1</item>
+    <dimen name="lb_guidedactions_section_shadow_width">16dp</dimen>
     <dimen name="lb_guidedactions_elevation">12dp</dimen>
     <dimen name="lb_guidedactions_selector_min_height">8dp</dimen>
     <dimen name="lb_guidedactions_vertical_padding">12dp</dimen>
 
+    <item name="lb_guidedactions_item_disabled_text_alpha" format="float" type="string">0.25</item>
+    <item name="lb_guidedactions_item_disabled_description_text_alpha" format="float" type="string">0.25</item>
     <item name="lb_guidedactions_item_unselected_text_alpha" format="float" type="string">1.00</item>
     <item name="lb_guidedactions_item_unselected_description_text_alpha" format="float" type="string">0.50</item>
     <item name="lb_guidedactions_item_enabled_chevron_alpha" format="float" type="string">1.00</item>
@@ -244,10 +248,10 @@
     <dimen name="lb_guidedactions_item_text_width">248dp</dimen>
     <dimen name="lb_guidedactions_item_text_width_no_icon">284dp</dimen>
     <dimen name="lb_guidedactions_item_min_height">64dp</dimen>
-    <dimen name="lb_guidedactions_item_start_padding">20dp</dimen>
+    <dimen name="lb_guidedactions_item_start_padding">28dp</dimen>
     <dimen name="lb_guidedactions_item_end_padding">28dp</dimen>
     <dimen name="lb_guidedactions_item_delimiter_padding">4dp</dimen>
-    <dimen name="lb_guidedactions_item_checkmark_diameter">8dp</dimen>
+    <dimen name="lb_guidedactions_item_checkmark_diameter">16dp</dimen>
     <dimen name="lb_guidedactions_item_icon_width">32dp</dimen>
     <dimen name="lb_guidedactions_item_icon_height">32dp</dimen>
     <dimen name="lb_guidedactions_item_title_font_size">18sp</dimen>
diff --git a/v17/leanback/res/values/ids.xml b/v17/leanback/res/values/ids.xml
index 6b67919..ca84efc8 100644
--- a/v17/leanback/res/values/ids.xml
+++ b/v17/leanback/res/values/ids.xml
@@ -16,7 +16,11 @@
 -->
  <resources>
      <item type="id" name="lb_focus_animator" />
+     <item type="id" name="lb_shadow_impl" />
      <item type="id" name="lb_slide_transition_value" />
+     <item type="id" name="transitionPosition" />
+
+     <item type="id" name="lb_guidedstep_background" />
 
      <item type="id" name="lb_control_play_pause" />
      <item type="id" name="lb_control_fast_forward" />
@@ -31,4 +35,10 @@
      <item type="id" name="lb_control_high_quality" />
      <item type="id" name="lb_control_closed_captioning" />
 
- </resources>
+      <item type="id" name="guidedactions_root2" />
+      <item type="id" name="guidedactions_list_background2" />
+      <item type="id" name="guidedactions_list2" />
+      <item type="id" name="guidedactions_selector2" />
+      <item type="id" name="guidedactions_content2" />
+
+</resources>
diff --git a/v17/leanback/res/values/integers.xml b/v17/leanback/res/values/integers.xml
index 8547e22..c9f3384 100644
--- a/v17/leanback/res/values/integers.xml
+++ b/v17/leanback/res/values/integers.xml
@@ -29,4 +29,11 @@
     <integer name="lb_playback_rows_fade_out_ms">250</integer>
     <integer name="lb_playback_rows_fade_delay_ms">100</integer>
     <integer name="lb_playback_controls_show_time_ms">3000</integer>
+
+    <!-- Gravity.LEFT -->
+    <integer name="slideEdgeStart">3</integer>
+    <!-- Gravity.RIGHT -->
+    <integer name="slideEdgeEnd">5</integer>
+
+    <integer name="lb_guidedstep_activity_background_fade_duration_ms">350</integer>
 </resources>
diff --git a/v17/leanback/res/values/strings.xml b/v17/leanback/res/values/strings.xml
index 2cd0ff11..3d93db2 100644
--- a/v17/leanback/res/values/strings.xml
+++ b/v17/leanback/res/values/strings.xml
@@ -75,4 +75,8 @@
     <!-- Talkback label for the control button to disable closed captioning -->
     <string name="lb_playback_controls_closed_captioning_disable">Disable Closed Captioning</string>
 
+    <!-- Title of standard Finish action for GuidedStepFragment -->
+    <string name="lb_guidedaction_finish_title">Finish</string>
+    <!-- Title of standard Continue action for GuidedStepFragment -->
+    <string name="lb_guidedaction_continue_title">Continue</string>
 </resources>
diff --git a/v17/leanback/res/values/styles.xml b/v17/leanback/res/values/styles.xml
index 3ee2821..3904467 100644
--- a/v17/leanback/res/values/styles.xml
+++ b/v17/leanback/res/values/styles.xml
@@ -87,14 +87,8 @@
     <style name="Widget.Leanback" parent="Widget.LeanbackBase" />
 
     <style name="Widget.Leanback.BaseCardViewStyle">
-        <item name="android:foreground">@drawable/lb_card_foreground</item>
-    </style>
-
-    <style name="Widget.Leanback.ImageCardViewStyle" parent="Widget.Leanback.BaseCardViewStyle">
-        <item name="cardType">infoUnder</item>
-        <item name="infoVisibility">activated</item>
-        <item name="android:background">@color/lb_basic_card_bg_color</item>
-        <item name="infoAreaBackground">@color/lb_basic_card_info_bg_color</item>
+        <item name="cardForeground">@drawable/lb_card_foreground</item>
+        <item name="cardBackground">@color/lb_basic_card_bg_color</item>
     </style>
 
     <style name="Widget.Leanback.TitleView" >
@@ -104,6 +98,77 @@
         <item name="android:paddingEnd">?attr/browsePaddingEnd</item>
     </style>
 
+    <style name="Widget.Leanback.ImageCardViewStyle" parent="Widget.Leanback.BaseCardViewStyle">
+        <item name="cardType">infoUnder</item>
+        <item name="infoVisibility">activated</item>
+        <!-- In order to keep backward compatibility we have to create an icon on right. -->
+        <item name="lbImageCardViewType">Title|Content|IconOnRight</item>
+        <item name="lbImageCardViewImageStyle">@style/Widget.Leanback.ImageCardView.ImageStyle</item>
+        <item name="lbImageCardViewTitleStyle">@style/Widget.Leanback.ImageCardView.TitleStyle</item>
+        <item name="lbImageCardViewContentStyle">@style/Widget.Leanback.ImageCardView.ContentStyle</item>
+        <item name="lbImageCardViewBadgeStyle">@style/Widget.Leanback.ImageCardView.BadgeStyle</item>
+        <item name="lbImageCardViewInfoAreaStyle">@style/Widget.Leanback.ImageCardView.InfoAreaStyle</item>
+        <!-- Deprecated. Use 'Widget.Leanback.ImageCardView.InfoAreaStyle' instead. -->
+        <item name="infoAreaBackground">@null</item>
+    </style>
+
+    <style name="Widget.Leanback.ImageCardView" />
+
+    <style name="Widget.Leanback.ImageCardView.ImageStyle">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:adjustViewBounds">true</item>
+        <item name="android:contentDescription">@null</item>
+        <item name="android:scaleType">centerCrop</item>
+        <item name="layout_viewType">main</item>
+    </style>
+
+    <style name="Widget.Leanback.ImageCardView.InfoAreaStyle">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_centerHorizontal">true</item>
+        <item name="layout_viewType">info</item>
+        <item name="android:paddingBottom">@dimen/lb_basic_card_info_padding_bottom</item>
+        <item name="android:paddingEnd">@dimen/lb_basic_card_info_padding_horizontal</item>
+        <item name="android:paddingStart">@dimen/lb_basic_card_info_padding_horizontal</item>
+        <item name="android:paddingTop">@dimen/lb_basic_card_info_padding_top</item>
+        <item name="android:background">@color/lb_basic_card_info_bg_color</item>
+    </style>
+	
+    <style name="Widget.Leanback.ImageCardView.TitleStyle">
+        <item name="android:id">@id/title_text</item>
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:maxLines">1</item>
+        <item name="android:layout_marginBottom">@dimen/lb_basic_card_info_text_margin</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:textColor">@color/lb_basic_card_title_text_color</item>
+        <item name="android:textSize">@dimen/lb_basic_card_title_text_size</item>
+        <item name="android:ellipsize">end</item>
+    </style>
+
+    <style name="Widget.Leanback.ImageCardView.ContentStyle">
+        <item name="android:id">@id/content_text</item>
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_alignParentStart">true</item>
+        <item name="android:layout_below">@+id/title_text</item>
+        <item name="android:layout_toStartOf">@+id/extra_badge</item>
+        <item name="android:maxLines">1</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:textColor">@color/lb_basic_card_content_text_color</item>
+        <item name="android:textSize">@dimen/lb_basic_card_content_text_size</item>
+        <item name="android:ellipsize">none</item>
+    </style>
+
+    <style name="Widget.Leanback.ImageCardView.BadgeStyle">
+        <item name="android:id">@id/extra_badge</item>
+        <item name="android:layout_width">@dimen/lb_basic_card_info_badge_size</item>
+        <item name="android:layout_height">@dimen/lb_basic_card_info_badge_size</item>
+        <item name="android:contentDescription">@null</item>
+        <item name="android:scaleType">fitCenter</item>
+    </style>
+
     <style name="Widget.Leanback.Title" />
 
     <style name="Widget.Leanback.Title.Text">
@@ -130,6 +195,7 @@
     <style name="Widget.Leanback.GridItems" />
 
     <style name="Widget.Leanback.Headers.VerticalGridView" >
+        <item name="android:background">?attr/defaultBrandColor</item>
         <item name="android:paddingStart">?attr/browsePaddingStart</item>
         <item name="focusOutFront">true</item>
         <item name="focusOutEnd">true</item>
@@ -357,21 +423,11 @@
         <item name="android:scaleType">fitCenter</item>
     </style>
 
-    <!-- Style for the container view in a GuidedActionsStylist's default layout. -->
-    <style name="Widget.Leanback.GuidedActionsContainerStyle">
-        <item name="android:layout_width">@dimen/lb_guidedactions_section_width</item>
-        <item name="android:layout_height">match_parent</item>
-        <item name="android:layout_alignParentEnd">true</item>
-        <item name="android:background">@color/lb_guidedactions_background</item>
-        <item name="android:elevation">@dimen/lb_guidedactions_elevation</item>
-    </style>
-
     <!-- Style for the selector view in a GuidedActionsStylist's default layout. -->
     <style name="Widget.Leanback.GuidedActionsSelectorStyle">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">@dimen/lb_guidedactions_selector_min_height</item>
         <item name="android:layout_centerVertical">true</item>
-        <item name="android:alpha">0</item>
         <item name="android:background">@color/lb_guidedactions_selector_color</item>
     </style>
 
@@ -401,9 +457,8 @@
         <item name="android:layout_height">@dimen/lb_guidedactions_item_checkmark_diameter</item>
         <item name="android:layout_gravity">center</item>
         <item name="android:layout_marginEnd">@dimen/lb_guidedactions_item_delimiter_padding</item>
-        <item name="android:scaleType">center</item>
-        <item name="android:src">@drawable/lb_guidedactions_item_checkmark</item>
-        <item name="android:visibility">invisible</item>
+        <item name="android:scaleType">centerInside</item>
+        <item name="android:visibility">gone</item>
     </style>
 
     <!-- Style for an action's icon in a GuidedActionsStylist's default item layout. -->
@@ -418,7 +473,7 @@
 
     <!-- Style for an action's text content in a GuidedActionsStylist's default item layout. -->
     <style name="Widget.Leanback.GuidedActionItemContentStyle">
-        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_gravity">start|center_vertical</item>
         <item name="android:layout_weight">1</item>
@@ -430,11 +485,12 @@
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:alpha">@string/lb_guidedactions_item_unselected_text_alpha</item>
-        <item name="android:ellipsize">marquee</item>
+        <item name="android:ellipsize">end</item>
         <item name="android:fontFamily">sans-serif-condensed</item>
         <item name="android:maxLines">@integer/lb_guidedactions_item_title_min_lines</item>
         <item name="android:textColor">@color/lb_guidedactions_item_unselected_text_color</item>
         <item name="android:textSize">@dimen/lb_guidedactions_item_title_font_size</item>
+        <item name="android:background">@null</item>
     </style>
 
     <!-- Style for an action's description in a GuidedActionsStylist's default item layout. -->
@@ -442,12 +498,13 @@
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:alpha">@string/lb_guidedactions_item_unselected_description_text_alpha</item>
-        <item name="android:ellipsize">marquee</item>
+        <item name="android:ellipsize">end</item>
         <item name="android:fontFamily">sans-serif-condensed</item>
         <item name="android:maxLines">@integer/lb_guidedactions_item_description_min_lines</item>
         <item name="android:textColor">@color/lb_guidedactions_item_unselected_text_color</item>
         <item name="android:textSize">@dimen/lb_guidedactions_item_description_font_size</item>
         <item name="android:visibility">gone</item>
+        <item name="android:background">@null</item>
     </style>
 
     <!-- Style for an action's chevron in a GuidedActionsStylist's default item layout. -->
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index 8178c50..36362dd 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -15,13 +15,14 @@
      limitations under the License.
 -->
 
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
 
     <!-- LeanbackBase may be overridden for specific api levels -->
     <style name="Theme.LeanbackBase" parent="android:Theme.Holo.NoActionBar">
         <item name="playbackProgressPrimaryColor">@color/lb_playback_progress_color_no_theme</item>
         <item name="playbackControlsIconHighlightColor">@color/lb_playback_icon_highlight_no_theme</item>
         <item name="defaultBrandColor">@color/lb_default_brand_color</item>
+        <item name="defaultBrandColorDark">@color/lb_default_brand_color_dark</item>
 
         <item name="android:windowOverscan">true</item>
         <item name="guidedStepTheme">@style/Theme.Leanback.GuidedStep</item>
@@ -95,6 +96,11 @@
         <item name="android:windowReturnTransition">@transition/lb_browse_return_transition</item>
     </style>
 
+    <style name="Theme.Leanback.VerticalGrid" parent="Theme.Leanback">
+        <item name="android:windowEnterTransition">@transition/lb_vertical_grid_enter_transition</item>
+        <item name="android:windowReturnTransition">@transition/lb_vertical_grid_return_transition</item>
+    </style>
+
     <style name="Theme.Leanback.Details" parent="Theme.Leanback">
         <item name="android:windowEnterTransition">@transition/lb_details_enter_transition</item>
         <item name="android:windowReturnTransition">@transition/lb_details_return_transition</item>
@@ -111,12 +117,18 @@
     <style name="Theme.Leanback.GuidedStep" parent="Theme.LeanbackBase">
         <item name="guidedStepThemeFlag">true</item>
 
-        <item name="guidedStepEntryAnimation">@animator/lb_guidedstep_slide_in_from_end</item>
-        <item name="guidedStepExitAnimation">@animator/lb_guidedstep_slide_out_to_start</item>
-        <item name="guidedStepReentryAnimation">@animator/lb_guidedstep_slide_in_from_start</item>
-        <item name="guidedStepReturnAnimation">@animator/lb_guidedstep_slide_out_to_end</item>
-        <item name="guidanceEntryAnimation">@animator/lb_guidance_entry</item>
-        <item name="guidedActionsEntryAnimation">@animator/lb_guidedactions_entry</item>
+        <item name="android:windowEnterTransition">@transition/lb_guidedstep_activity_enter</item>
+
+        <!-- background applied to each GuidedStepFragment by default-->
+        <item name="guidedStepBackground">?android:attr/colorBackground</item>
+        <!-- Each GuidedStepFragment has a background so activity does not need a background.
+             But We still need a dumb background to keep the temporary translucent state last
+             as long as the background view fade-in transition -->
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowTransitionBackgroundFadeDuration">@integer/lb_guidedstep_activity_background_fade_duration_ms</item>
+
+        <item name="guidedStepImeAppearingAnimation">@animator/lb_guidedstep_slide_up</item>
+        <item name="guidedStepImeDisappearingAnimation">@animator/lb_guidedstep_slide_down</item>
 
         <item name="guidanceContainerStyle">@style/Widget.Leanback.GuidanceContainerStyle</item>
         <item name="guidanceIconStyle">@style/Widget.Leanback.GuidanceIconStyle</item>
@@ -124,7 +136,9 @@
         <item name="guidanceBreadcrumbStyle">@style/Widget.Leanback.GuidanceBreadcrumbStyle</item>
         <item name="guidanceDescriptionStyle">@style/Widget.Leanback.GuidanceDescriptionStyle</item>
 
-        <item name="guidedActionsContainerStyle">@style/Widget.Leanback.GuidedActionsContainerStyle</item>
+        <item name="guidedActionsElevation">@dimen/lb_guidedactions_elevation</item>
+        <item name="guidedActionsBackground">@color/lb_guidedactions_background</item>
+        <item name="guidedActionsBackgroundDark">@color/lb_guidedactions_background_dark</item>
         <item name="guidedActionsSelectorStyle">@style/Widget.Leanback.GuidedActionsSelectorStyle</item>
         <item name="guidedActionsListStyle">@style/Widget.Leanback.GuidedActionsListStyle</item>
         <item name="guidedActionsSelectorShowAnimation">@animator/lb_guidedactions_selector_show</item>
@@ -138,14 +152,12 @@
         <item name="guidedActionItemDescriptionStyle">@style/Widget.Leanback.GuidedActionItemDescriptionStyle</item>
         <item name="guidedActionItemChevronStyle">@style/Widget.Leanback.GuidedActionItemChevronStyle</item>
 
-        <item name="guidedActionCheckedAnimation">@animator/lb_guidedactions_item_checked</item>
-        <item name="guidedActionUncheckedAnimation">@animator/lb_guidedactions_item_unchecked</item>
         <item name="guidedActionPressedAnimation">@animator/lb_guidedactions_item_pressed</item>
         <item name="guidedActionUnpressedAnimation">@animator/lb_guidedactions_item_unpressed</item>
         <item name="guidedActionEnabledChevronAlpha">@string/lb_guidedactions_item_enabled_chevron_alpha</item>
         <item name="guidedActionDisabledChevronAlpha">@string/lb_guidedactions_item_disabled_chevron_alpha</item>
-        <item name="guidedActionContentWidth">@dimen/lb_guidedactions_item_text_width</item>
-        <item name="guidedActionContentWidthNoIcon">@dimen/lb_guidedactions_item_text_width_no_icon</item>
+        <item name="guidedActionContentWidthWeight">@string/lb_guidedactions_width_weight</item>
+        <item name="guidedActionContentWidthWeightTwoPanels">@string/lb_guidedactions_width_weight_two_panels</item>
         <item name="guidedActionTitleMinLines">@integer/lb_guidedactions_item_title_min_lines</item>
         <item name="guidedActionTitleMaxLines">@integer/lb_guidedactions_item_title_max_lines</item>
         <item name="guidedActionDescriptionMinLines">@integer/lb_guidedactions_item_description_min_lines</item>
diff --git a/v17/leanback/src/android/support/v17/leanback/animation/UntargetableAnimatorSet.java b/v17/leanback/src/android/support/v17/leanback/animation/UntargetableAnimatorSet.java
deleted file mode 100644
index 9cdbc0c..0000000
--- a/v17/leanback/src/android/support/v17/leanback/animation/UntargetableAnimatorSet.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.
- */
-package android.support.v17.leanback.animation;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.TimeInterpolator;
-
-import java.util.ArrayList;
-
-/**
- * Custom fragment animations supplied by Fragment.onCreateAnimator have their targets set to the
- * fragment's main view by the fragment manager.  Sometimes, this isn't what you want; you may be
- * supplying a heterogeneous collection of animations that already have targets. This class helps
- * you return such a collection of animations from onCreateAnimator without having their targets
- * reset.
- *
- * Note that one does not simply subclass AnimatorSet and override setTarget() because AnimatorSet
- * is final.
- * @hide
- */
-public class UntargetableAnimatorSet extends Animator {
-
-    private final AnimatorSet mAnimatorSet;
-
-    public UntargetableAnimatorSet(AnimatorSet animatorSet) {
-        mAnimatorSet = animatorSet;
-    }
-
-    @Override
-    public void addListener(Animator.AnimatorListener listener) {
-        mAnimatorSet.addListener(listener);
-    }
-
-    @Override
-    public void cancel() {
-        mAnimatorSet.cancel();
-    }
-
-    @Override
-    public Animator clone() {
-        return mAnimatorSet.clone();
-    }
-
-    @Override
-    public void end() {
-        mAnimatorSet.end();
-    }
-
-    @Override
-    public long getDuration() {
-        return mAnimatorSet.getDuration();
-    }
-
-    @Override
-    public ArrayList<Animator.AnimatorListener> getListeners() {
-        return mAnimatorSet.getListeners();
-    }
-
-    @Override
-    public long getStartDelay() {
-        return mAnimatorSet.getStartDelay();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return mAnimatorSet.isRunning();
-    }
-
-    @Override
-    public boolean isStarted() {
-        return mAnimatorSet.isStarted();
-    }
-
-    @Override
-    public void removeAllListeners() {
-        mAnimatorSet.removeAllListeners();
-    }
-
-    @Override
-    public void removeListener(Animator.AnimatorListener listener) {
-        mAnimatorSet.removeListener(listener);
-    }
-
-    @Override
-    public Animator setDuration(long duration) {
-        return mAnimatorSet.setDuration(duration);
-    }
-
-    @Override
-    public void setInterpolator(TimeInterpolator value) {
-        mAnimatorSet.setInterpolator(value);
-    }
-
-    @Override
-    public void setStartDelay(long startDelay) {
-        mAnimatorSet.setStartDelay(startDelay);
-    }
-
-    @Override
-    public void setTarget(Object target) {
-        // ignore
-    }
-
-    @Override
-    public void setupEndValues() {
-        mAnimatorSet.setupEndValues();
-    }
-
-    @Override
-    public void setupStartValues() {
-        mAnimatorSet.setupStartValues();
-    }
-
-    @Override
-    public void start() {
-        mAnimatorSet.start();
-    }
-}
-
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
index 5b2deac..c878a86 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
@@ -30,8 +30,6 @@
     private boolean mEntranceTransitionPreparePending = false;
     private Object mEntranceTransition;
 
-    static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
-
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
@@ -176,7 +174,7 @@
         if (mEntranceTransition == null) {
             return;
         }
-        sTransitionHelper.setTransitionListener(mEntranceTransition, new TransitionListener() {
+        TransitionHelper.addTransitionListener(mEntranceTransition, new TransitionListener() {
             @Override
             public void onTransitionEnd(Object transition) {
                 mEntranceTransition = null;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
index a72bb5b..b9c7d58 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
@@ -32,8 +32,6 @@
     private boolean mEntranceTransitionPreparePending = false;
     private Object mEntranceTransition;
 
-    static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
-
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
@@ -178,7 +176,7 @@
         if (mEntranceTransition == null) {
             return;
         }
-        sTransitionHelper.setTransitionListener(mEntranceTransition, new TransitionListener() {
+        TransitionHelper.addTransitionListener(mEntranceTransition, new TransitionListener() {
             @Override
             public void onTransitionEnd(Object transition) {
                 mEntranceTransition = null;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
index 7e8f02f..8c417a4 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -425,7 +425,7 @@
                 if (mBrowseTransitionListener != null) {
                     mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
                 }
-                sTransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
+                TransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
                         mHeadersTransition);
                 if (mHeadersBackStackEnabled) {
                     if (!withHeaders) {
@@ -622,19 +622,19 @@
             mHeadersFragment.setBackgroundColor(mBrandColor);
         }
 
-        mSceneWithHeaders = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
             @Override
             public void run() {
                 showHeaders(true);
             }
         });
-        mSceneWithoutHeaders =  sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
             @Override
             public void run() {
                 showHeaders(false);
             }
         });
-        mSceneAfterEntranceTransition = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
             @Override
             public void run() {
                 setEntranceTransitionEndState();
@@ -644,11 +644,11 @@
     }
 
     private void createHeadersTransition() {
-        mHeadersTransition = sTransitionHelper.loadTransition(getActivity(),
+        mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
                 mShowingHeaders ?
                 R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
 
-        sTransitionHelper.setTransitionListener(mHeadersTransition, new TransitionListener() {
+        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
             @Override
             public void onTransitionStart(Object transition) {
             }
@@ -891,14 +891,13 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return sTransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(getActivity(),
                 R.transition.lb_browse_entrance_transition);
     }
 
     @Override
     protected void runEntranceTransition(Object entranceTransition) {
-        sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
-                entranceTransition);
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
     }
 
     @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
index 44deec4..fa7f61e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -427,7 +427,7 @@
                 if (mBrowseTransitionListener != null) {
                     mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
                 }
-                sTransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
+                TransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
                         mHeadersTransition);
                 if (mHeadersBackStackEnabled) {
                     if (!withHeaders) {
@@ -624,19 +624,19 @@
             mHeadersSupportFragment.setBackgroundColor(mBrandColor);
         }
 
-        mSceneWithHeaders = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
             @Override
             public void run() {
                 showHeaders(true);
             }
         });
-        mSceneWithoutHeaders =  sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
             @Override
             public void run() {
                 showHeaders(false);
             }
         });
-        mSceneAfterEntranceTransition = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
             @Override
             public void run() {
                 setEntranceTransitionEndState();
@@ -646,11 +646,11 @@
     }
 
     private void createHeadersTransition() {
-        mHeadersTransition = sTransitionHelper.loadTransition(getActivity(),
+        mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
                 mShowingHeaders ?
                 R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
 
-        sTransitionHelper.setTransitionListener(mHeadersTransition, new TransitionListener() {
+        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
             @Override
             public void onTransitionStart(Object transition) {
             }
@@ -893,14 +893,13 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return sTransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(getActivity(),
                 R.transition.lb_browse_entrance_transition);
     }
 
     @Override
     protected void runEntranceTransition(Object entranceTransition) {
-        sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
-                entranceTransition);
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
     }
 
     @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
index d415de0..ddafd5f 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
@@ -14,6 +14,7 @@
 package android.support.v17.leanback.app;
 
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.widget.BrowseFrameLayout;
 import android.support.v17.leanback.widget.DetailsOverviewRow;
 import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
@@ -200,7 +201,7 @@
             }
         }
 
-        mSceneAfterEntranceTransition = sTransitionHelper.createScene(
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(
                 (ViewGroup) view, new Runnable() {
             @Override
             public void run() {
@@ -394,25 +395,20 @@
         super.onStart();
         setupChildFragmentLayout();
         setupFocusSearchListener();
-        mRowsFragment.getView().requestFocus();
         if (isEntranceTransitionEnabled()) {
-            // make sure recycler view animation is disabled
-            mRowsFragment.onTransitionPrepare();
-            mRowsFragment.onTransitionStart();
             mRowsFragment.setEntranceTransitionState(false);
         }
     }
 
     @Override
     protected Object createEntranceTransition() {
-        return sTransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(getActivity(),
                 R.transition.lb_details_enter_transition);
     }
 
     @Override
     protected void runEntranceTransition(Object entranceTransition) {
-        sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
-                entranceTransition);
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
     }
 
     @Override
@@ -420,4 +416,13 @@
         mRowsFragment.onTransitionEnd();
     }
 
+    @Override
+    protected void onEntranceTransitionPrepare() {
+        mRowsFragment.onTransitionPrepare();
+    }
+
+    @Override
+    protected void onEntranceTransitionStart() {
+        mRowsFragment.onTransitionStart();
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
index afaf5a8..7532d79 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -16,6 +16,7 @@
 package android.support.v17.leanback.app;
 
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.widget.BrowseFrameLayout;
 import android.support.v17.leanback.widget.DetailsOverviewRow;
 import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
@@ -202,7 +203,7 @@
             }
         }
 
-        mSceneAfterEntranceTransition = sTransitionHelper.createScene(
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(
                 (ViewGroup) view, new Runnable() {
             @Override
             public void run() {
@@ -396,25 +397,20 @@
         super.onStart();
         setupChildFragmentLayout();
         setupFocusSearchListener();
-        mRowsSupportFragment.getView().requestFocus();
         if (isEntranceTransitionEnabled()) {
-            // make sure recycler view animation is disabled
-            mRowsSupportFragment.onTransitionPrepare();
-            mRowsSupportFragment.onTransitionStart();
             mRowsSupportFragment.setEntranceTransitionState(false);
         }
     }
 
     @Override
     protected Object createEntranceTransition() {
-        return sTransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(getActivity(),
                 R.transition.lb_details_enter_transition);
     }
 
     @Override
     protected void runEntranceTransition(Object entranceTransition) {
-        sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
-                entranceTransition);
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
     }
 
     @Override
@@ -422,4 +418,13 @@
         mRowsSupportFragment.onTransitionEnd();
     }
 
+    @Override
+    protected void onEntranceTransitionPrepare() {
+        mRowsSupportFragment.onTransitionPrepare();
+    }
+
+    @Override
+    protected void onEntranceTransitionStart() {
+        mRowsSupportFragment.onTransitionStart();
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
index 41ecac9..142e971 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
@@ -19,6 +19,7 @@
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.GuidedAction;
 import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.support.v17.leanback.widget.ImeKeyMonitor;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.util.Log;
@@ -26,9 +27,14 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -43,6 +49,9 @@
     private static final String TAG = "GuidedActionAdapter";
     private static final boolean DEBUG = false;
 
+    private static final String TAG_EDIT = "EditableAction";
+    private static final boolean DEBUG_EDIT = false;
+
     /**
      * Object listening for click events within a {@link GuidedActionAdapter}.
      */
@@ -66,11 +75,32 @@
     }
 
     /**
+     * Object listening for edit events within a {@link GuidedActionAdapter}.
+     */
+    public interface EditListener {
+
+        /**
+         * Called when the user exits edit mode on an action.
+         */
+        public long onGuidedActionEdited(GuidedAction action);
+
+        /**
+         * Called when Ime Open
+         */
+        public void onImeOpen();
+
+        /**
+         * Called when Ime Close
+         */
+        public void onImeClose();
+    }
+
+    /**
      * View holder containing a {@link GuidedAction}.
      */
-    private static class ActionViewHolder extends ViewHolder {
+    static class ActionViewHolder extends ViewHolder {
 
-        private final GuidedActionsStylist.ViewHolder mStylistViewHolder;
+        final GuidedActionsStylist.ViewHolder mStylistViewHolder;
         private GuidedAction mAction;
 
         /**
@@ -98,30 +128,36 @@
         }
     }
 
-    private RecyclerView mRecyclerView;
     private final ActionOnKeyListener mActionOnKeyListener;
     private final ActionOnFocusListener mActionOnFocusListener;
+    private final ActionEditListener mActionEditListener;
     private final List<GuidedAction> mActions;
     private ClickListener mClickListener;
-    private GuidedActionsStylist mStylist;
+    private final GuidedActionsStylist mStylist;
     private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            if (v != null && v.getWindowToken() != null && mClickListener != null) {
-                ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
+            if (v != null && v.getWindowToken() != null && getRecyclerView() != null) {
+                ActionViewHolder avh = (ActionViewHolder)getRecyclerView().getChildViewHolder(v);
                 GuidedAction action = avh.getAction();
-                if (action.isEnabled() && !action.infoOnly()) {
-                    mClickListener.onGuidedActionClicked(action);
+                if (action.isEditable() || action.isDescriptionEditable()) {
+                    if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme by click");
+                    mGroup.openIme(GuidedActionAdapter.this, avh);
+                } else {
+                    handleCheckedActions(avh);
+                    if (action.isEnabled() && !action.infoOnly()) {
+                        performOnActionClick(avh);
+                    }
                 }
             }
         }
     };
+    GuidedActionAdapterGroup mGroup;
 
     /**
      * Constructs a GuidedActionAdapter with the given list of guided actions, the given click and
      * focus listeners, and the given presenter.
      * @param actions The list of guided actions this adapter will manage.
-     * @param clickListener The click listener for items in this adapter.
      * @param focusListener The focus listener for items in this adapter.
      * @param presenter The presenter that will manage the display of items in this adapter.
      */
@@ -131,8 +167,9 @@
         mActions = new ArrayList<GuidedAction>(actions);
         mClickListener = clickListener;
         mStylist = presenter;
-        mActionOnKeyListener = new ActionOnKeyListener(clickListener, mActions);
+        mActionOnKeyListener = new ActionOnKeyListener();
         mActionOnFocusListener = new ActionOnFocusListener(focusListener);
+        mActionEditListener = new ActionEditListener();
     }
 
     /**
@@ -164,12 +201,27 @@
     }
 
     /**
+     * Return index of action in array
+     * @param action Action to search index.
+     * @return Index of Action in array.
+     */
+    public int indexOf(GuidedAction action) {
+        return mActions.indexOf(action);
+    }
+
+    /**
+     * @return GuidedActionsStylist used to build the actions list UI.
+     */
+    public GuidedActionsStylist getGuidedActionsStylist() {
+        return mStylist;
+    }
+
+    /**
      * Sets the click listener for items managed by this adapter.
      * @param clickListener The click listener for this adapter.
      */
     public void setClickListener(ClickListener clickListener) {
         mClickListener = clickListener;
-        mActionOnKeyListener.setListener(clickListener);
     }
 
     /**
@@ -192,16 +244,12 @@
      * {@inheritDoc}
      */
     @Override
-    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-        mRecyclerView = recyclerView;
+    public int getItemViewType(int position) {
+        return mStylist.getItemViewType(mActions.get(position));
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
-        mRecyclerView = null;
+    private RecyclerView getRecyclerView() {
+        return mStylist.getActionsGridView();
     }
 
     /**
@@ -209,15 +257,29 @@
      */
     @Override
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        GuidedActionsStylist.ViewHolder vh = mStylist.onCreateViewHolder(parent);
+        GuidedActionsStylist.ViewHolder vh = mStylist.onCreateViewHolder(parent, viewType);
         View v = vh.view;
         v.setOnKeyListener(mActionOnKeyListener);
         v.setOnClickListener(mOnClickListener);
         v.setOnFocusChangeListener(mActionOnFocusListener);
 
+        setupListeners(vh.getEditableTitleView());
+        setupListeners(vh.getEditableDescriptionView());
+
         return new ActionViewHolder(v, vh);
     }
 
+    private void setupListeners(EditText edit) {
+        if (edit != null) {
+            edit.setPrivateImeOptions("EscapeNorth=1;");
+            edit.setOnEditorActionListener(mActionEditListener);
+            if (edit instanceof ImeKeyMonitor) {
+                ImeKeyMonitor monitor = (ImeKeyMonitor)edit;
+                monitor.setImeKeyListener(mActionEditListener);
+            }
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -226,7 +288,7 @@
         if (position >= mActions.size()) {
             return;
         }
-        ActionViewHolder avh = (ActionViewHolder)holder;
+        final ActionViewHolder avh = (ActionViewHolder)holder;
         GuidedAction action = mActions.get(position);
         avh.setAction(action);
         mStylist.onBindViewHolder(avh.mStylistViewHolder, action);
@@ -254,8 +316,8 @@
         }
 
         public void unFocus() {
-            if (mSelectedView != null) {
-                ViewHolder vh = mRecyclerView.getChildViewHolder(mSelectedView);
+            if (mSelectedView != null && getRecyclerView() != null) {
+                ViewHolder vh = getRecyclerView().getChildViewHolder(mSelectedView);
                 if (vh != null) {
                     ActionViewHolder avh = (ActionViewHolder)vh;
                     mStylist.onAnimateItemFocused(avh.mStylistViewHolder, false);
@@ -268,8 +330,10 @@
 
         @Override
         public void onFocusChange(View v, boolean hasFocus) {
-            ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
-            mStylist.onAnimateItemFocused(avh.mStylistViewHolder, hasFocus);
+            if (getRecyclerView() == null) {
+                return;
+            }
+            ActionViewHolder avh = (ActionViewHolder) getRecyclerView().getChildViewHolder(v);
             if (hasFocus) {
                 mSelectedView = v;
                 if (mFocusListener != null) {
@@ -279,27 +343,74 @@
                 }
             } else {
                 if (mSelectedView == v) {
+                    mStylist.onAnimateItemPressedCancelled(avh.mStylistViewHolder);
                     mSelectedView = null;
                 }
             }
+            mStylist.onAnimateItemFocused(avh.mStylistViewHolder, hasFocus);
+        }
+    }
+
+    public ActionViewHolder findSubChildViewHolder(View v) {
+        // Needed because RecyclerView.getChildViewHolder does not traverse the hierarchy
+        if (getRecyclerView() == null) {
+            return null;
+        }
+        ActionViewHolder result = null;
+        ViewParent parent = v.getParent();
+        while (parent != getRecyclerView() && parent != null && v != null) {
+            v = (View)parent;
+            parent = parent.getParent();
+        }
+        if (parent != null && v != null) {
+            result = (ActionViewHolder)getRecyclerView().getChildViewHolder(v);
+        }
+        return result;
+    }
+
+    public void handleCheckedActions(ActionViewHolder avh) {
+        GuidedAction action = avh.getAction();
+        int actionCheckSetId = action.getCheckSetId();
+        if (getRecyclerView() != null && actionCheckSetId != GuidedAction.NO_CHECK_SET) {
+            // Find any actions that are checked and are in the same group
+            // as the selected action. Fade their checkmarks out.
+            if (actionCheckSetId != GuidedAction.CHECKBOX_CHECK_SET_ID) {
+                for (int i = 0, size = mActions.size(); i < size; i++) {
+                    GuidedAction a = mActions.get(i);
+                    if (a != action && a.getCheckSetId() == actionCheckSetId && a.isChecked()) {
+                        a.setChecked(false);
+                        ViewHolder vh = getRecyclerView().findViewHolderForPosition(i);
+                        if (vh != null) {
+                            GuidedActionsStylist.ViewHolder subViewHolder =
+                                    ((ActionViewHolder)vh).mStylistViewHolder;
+                            mStylist.onAnimateItemChecked(subViewHolder, false);
+                        }
+                    }
+                }
+            }
+
+            // If we we'ren't already checked, fade our checkmark in.
+            if (!action.isChecked()) {
+                action.setChecked(true);
+                mStylist.onAnimateItemChecked(avh.mStylistViewHolder, true);
+            } else {
+                if (actionCheckSetId == GuidedAction.CHECKBOX_CHECK_SET_ID) {
+                    action.setChecked(false);
+                    mStylist.onAnimateItemChecked(avh.mStylistViewHolder, false);
+                }
+            }
         }
     }
 
+    public void performOnActionClick(ActionViewHolder avh) {
+        if (mClickListener != null) {
+            mClickListener.onGuidedActionClicked(avh.getAction());
+        }
+    }
+
     private class ActionOnKeyListener implements View.OnKeyListener {
 
-        private final List<GuidedAction> mActions;
         private boolean mKeyPressed = false;
-        private ClickListener mClickListener;
-
-        public ActionOnKeyListener(ClickListener listener,
-                List<GuidedAction> actions) {
-            mClickListener = listener;
-            mActions = actions;
-        }
-
-        public void setListener(ClickListener listener) {
-            mClickListener = listener;
-        }
 
         private void playSound(View v, int soundEffect) {
             if (v.isSoundEffectsEnabled()) {
@@ -314,7 +425,7 @@
          */
         @Override
         public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (v == null || event == null) {
+            if (v == null || event == null || getRecyclerView() == null) {
                 return false;
             }
             boolean handled = false;
@@ -325,7 +436,8 @@
                 case KeyEvent.KEYCODE_BUTTON_Y:
                 case KeyEvent.KEYCODE_ENTER:
 
-                    ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
+                    ActionViewHolder avh = (ActionViewHolder) getRecyclerView()
+                            .getChildViewHolder(v);
                     GuidedAction action = avh.getAction();
 
                     if (!action.isEnabled() || action.infoOnly()) {
@@ -338,33 +450,25 @@
 
                     switch (event.getAction()) {
                         case KeyEvent.ACTION_DOWN:
+                            if (DEBUG) {
+                                Log.d(TAG, "Enter Key down");
+                            }
                             if (!mKeyPressed) {
                                 mKeyPressed = true;
-
                                 playSound(v, AudioManager.FX_KEY_CLICK);
-
-                                if (DEBUG) {
-                                    Log.d(TAG, "Enter Key down");
-                                }
-
                                 mStylist.onAnimateItemPressed(avh.mStylistViewHolder,
                                         mKeyPressed);
-                                handled = true;
                             }
                             break;
                         case KeyEvent.ACTION_UP:
+                            if (DEBUG) {
+                                Log.d(TAG, "Enter Key up");
+                            }
+                            // Sometimes we are losing ACTION_DOWN for the first ENTER after pressed
+                            // Escape in IME.
                             if (mKeyPressed) {
                                 mKeyPressed = false;
-
-                                if (DEBUG) {
-                                    Log.d(TAG, "Enter Key up");
-                                }
-
-                                mStylist.onAnimateItemPressed(avh.mStylistViewHolder,
-                                            mKeyPressed);
-                                handleCheckedActions(avh, action);
-                                mClickListener.onGuidedActionClicked(action);
-                                handled = true;
+                                mStylist.onAnimateItemPressed(avh.mStylistViewHolder, mKeyPressed);
                             }
                             break;
                         default:
@@ -377,30 +481,40 @@
             return handled;
         }
 
-        private void handleCheckedActions(ActionViewHolder avh, GuidedAction action) {
-            int actionCheckSetId = action.getCheckSetId();
-            if (actionCheckSetId != GuidedAction.NO_CHECK_SET) {
-                // Find any actions that are checked and are in the same group
-                // as the selected action. Fade their checkmarks out.
-                for (int i = 0, size = mActions.size(); i < size; i++) {
-                    GuidedAction a = mActions.get(i);
-                    if (a != action && a.getCheckSetId() == actionCheckSetId && a.isChecked()) {
-                        a.setChecked(false);
-                        ViewHolder vh = mRecyclerView.findViewHolderForPosition(i);
-                        if (vh != null) {
-                            GuidedActionsStylist.ViewHolder subViewHolder =
-                                    ((ActionViewHolder)vh).mStylistViewHolder;
-                            mStylist.onAnimateItemChecked(subViewHolder, false);
-                        }
-                    }
-                }
-
-                // If we we'ren't already checked, fade our checkmark in.
-                if (!action.isChecked()) {
-                    action.setChecked(true);
-                    mStylist.onAnimateItemChecked(avh.mStylistViewHolder, true);
-                }
-            }
-        }
     }
+
+    private class ActionEditListener implements OnEditorActionListener,
+            ImeKeyMonitor.ImeKeyListener {
+
+        @Override
+        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+            if (DEBUG_EDIT) Log.v(TAG_EDIT, "IME action: " + actionId);
+            boolean handled = false;
+            if (actionId == EditorInfo.IME_ACTION_NEXT ||
+                actionId == EditorInfo.IME_ACTION_DONE) {
+                mGroup.fillAndGoNext(GuidedActionAdapter.this, v);
+                handled = true;
+            } else if (actionId == EditorInfo.IME_ACTION_NONE) {
+                if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme escape north");
+                // Escape north handling: stay on current item, but close editor
+                handled = true;
+                mGroup.fillAndStay(GuidedActionAdapter.this, v);
+            }
+            return handled;
+        }
+
+        @Override
+        public boolean onKeyPreIme(EditText editText, int keyCode, KeyEvent event) {
+            if (DEBUG_EDIT) Log.v(TAG_EDIT, "IME key: " + keyCode);
+            if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
+                mGroup.fillAndStay(GuidedActionAdapter.this, editText);
+            } else if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() ==
+                    KeyEvent.ACTION_UP) {
+                mGroup.fillAndGoNext(GuidedActionAdapter.this, editText);
+            }
+            return false;
+        }
+
+    }
+
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java
new file mode 100644
index 0000000..8f8951c
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.content.Context;
+import android.support.v17.leanback.app.GuidedActionAdapter.ActionViewHolder;
+import android.support.v17.leanback.app.GuidedActionAdapter.ClickListener;
+import android.support.v17.leanback.app.GuidedActionAdapter.EditListener;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.ImeKeyMonitor;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import java.util.ArrayList;
+
+/**
+ * Internal implementation manages a group of GuidedActionAdapters, control the next action after
+ * editing finished, maintain the Ime open/close status.
+ */
+class GuidedActionAdapterGroup {
+
+    private static final String TAG_EDIT = "EditableAction";
+    private static final boolean DEBUG_EDIT = false;
+
+    ArrayList<GuidedActionAdapter> mAdapters = new ArrayList<GuidedActionAdapter>();
+    private boolean mImeOpened;
+    private EditListener mEditListener;
+
+    GuidedActionAdapterGroup() {
+    }
+
+    public void addAdpter(GuidedActionAdapter adapter) {
+        mAdapters.add(adapter);
+        adapter.mGroup = this;
+    }
+
+    public void setEditListener(EditListener listener) {
+        mEditListener = listener;
+    }
+
+    boolean focusToNextAction(GuidedActionAdapter adapter, GuidedAction action, long nextActionId) {
+        // for ACTION_ID_NEXT, we first find out the matching index in Actions list.
+        int index = 0;
+        if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
+            index = adapter.indexOf(action);
+            if (index < 0) {
+                return false;
+            }
+            // start from next, if reach end, will go next Adapter below
+            index++;
+        }
+
+        int adapterIndex = mAdapters.indexOf(adapter);
+        do {
+            int size = adapter.getCount();
+            if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
+                while (index < size && !adapter.getItem(index).isFocusable()) {
+                    index++;
+                }
+            } else {
+                while (index < size && adapter.getItem(index).getId() != nextActionId) {
+                    index++;
+                }
+            }
+            if (index < size) {
+                ActionViewHolder vh = (ActionViewHolder) adapter.getGuidedActionsStylist()
+                        .getActionsGridView().findViewHolderForPosition(index);
+                if (vh != null) {
+                    if (vh.getAction().isEditable() || vh.getAction().isDescriptionEditable()) {
+                        if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme of next Action");
+                        // open Ime on next action.
+                        openIme(adapter, vh);
+                    } else {
+                        if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme and focus to next Action");
+                        // close IME and focus to next (not editable) action
+                        closeIme(vh.mStylistViewHolder.view);
+                        vh.mStylistViewHolder.view.requestFocus();
+                    }
+                    return true;
+                }
+                return false;
+            }
+            // search from index 0 of next Adapter
+            adapterIndex++;
+            if (adapterIndex >= mAdapters.size()) {
+                break;
+            }
+            adapter = mAdapters.get(adapterIndex);
+            index = 0;
+        } while (true);
+        return false;
+    }
+
+    public void openIme(GuidedActionAdapter adapter, ActionViewHolder avh) {
+        adapter.getGuidedActionsStylist().setEditingMode(avh.mStylistViewHolder, avh.getAction(),
+                true);
+        View v = avh.mStylistViewHolder.getEditingView();
+        if (v == null) {
+            return;
+        }
+        InputMethodManager mgr = (InputMethodManager)
+                v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+        v.requestFocus();
+        mgr.showSoftInput(v, 0);
+        if (!mImeOpened) {
+            mImeOpened = true;
+            mEditListener.onImeOpen();
+        }
+    }
+
+    public void closeIme(View v) {
+        if (mImeOpened) {
+            mImeOpened = false;
+            InputMethodManager mgr = (InputMethodManager)
+                    v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+            mgr.hideSoftInputFromWindow(v.getWindowToken(), 0);
+            mEditListener.onImeClose();
+        }
+    }
+
+    private long finishEditing(GuidedActionAdapter adapter, ActionViewHolder avh) {
+        long nextActionId = mEditListener.onGuidedActionEdited(avh.getAction());
+        adapter.getGuidedActionsStylist().setEditingMode(avh.mStylistViewHolder, avh.getAction(),
+                false);
+        return nextActionId;
+    }
+
+    public void fillAndStay(GuidedActionAdapter adapter, TextView v) {
+        ActionViewHolder avh = adapter.findSubChildViewHolder(v);
+        updateTextIntoAction(avh, v);
+        finishEditing(adapter, avh);
+        closeIme(v);
+        avh.mStylistViewHolder.view.requestFocus();
+    }
+
+    public void fillAndGoNext(GuidedActionAdapter adapter, TextView v) {
+        boolean handled = false;
+        ActionViewHolder avh = adapter.findSubChildViewHolder(v);
+        updateTextIntoAction(avh, v);
+        adapter.performOnActionClick(avh);
+        long nextActionId = finishEditing(adapter, avh);
+        if (nextActionId != GuidedAction.ACTION_ID_CURRENT
+                && nextActionId != avh.getAction().getId()) {
+            handled = focusToNextAction(adapter, avh.getAction(), nextActionId);
+        }
+        if (!handled) {
+            if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme no next action");
+            handled = true;
+            closeIme(v);
+            avh.mStylistViewHolder.view.requestFocus();
+        }
+    }
+
+    private void updateTextIntoAction(ActionViewHolder avh, TextView v) {
+        GuidedAction action = avh.getAction();
+        if (v == avh.mStylistViewHolder.getDescriptionView()) {
+            if (action.getEditDescription() != null) {
+                action.setEditDescription(v.getText());
+            } else {
+                action.setDescription(v.getText());
+            }
+        } else if (v == avh.mStylistViewHolder.getTitleView()) {
+            if (action.getEditTitle() != null) {
+                action.setEditTitle(v.getText());
+            } else {
+                action.setTitle(v.getText());
+            }
+        }
+    }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
index b1e87a1..8be8f24 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
@@ -18,28 +18,34 @@
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
+import android.app.FragmentManager.BackStackEntry;
 import android.app.FragmentTransaction;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
-import android.support.v17.leanback.animation.UntargetableAnimatorSet;
+import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
 import android.support.v17.leanback.widget.GuidedAction;
 import android.support.v17.leanback.widget.GuidedActionsStylist;
 import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import java.util.ArrayList;
@@ -52,7 +58,7 @@
  * <p>
  * <h3>Basic Usage</h3>
  * <p>
- * Clients of GuidedStepFragment typically create a custom subclass to attach to their Activities.
+ * Clients of GuidedStepFragment must create a custom subclass to attach to their Activities.
  * This custom subclass provides the information necessary to construct the user interface and
  * respond to user actions. At a minimum, subclasses should override:
  * <ul>
@@ -61,6 +67,19 @@
  * <li>{@link #onGuidedActionClicked}, to respond to those actions</li>
  * </ul>
  * <p>
+ * Clients use following helper functions to add GuidedStepFragment to Activity or FragmentManager:
+ * <ul>
+ * <li>{@link #addAsRoot(Activity, GuidedStepFragment, int)}, to be called during Activity onCreate,
+ * adds GuidedStepFragment as the first Fragment in activity.</li>
+ * <li>{@link #add(FragmentManager, GuidedStepFragment)} or {@link #add(FragmentManager,
+ * GuidedStepFragment, int)}, to add GuidedStepFragment on top of existing Fragments or
+ * replacing existing GuidedStepFragment when moving forward to next step.</li>
+ * <li>{@link #finishGuidedStepFragments()} can either finish the activity or pop all
+ * GuidedStepFragment from stack.
+ * <li>If app chooses not to use the helper function, it is the app's responsibility to call
+ * {@link #setUiStyle(int)} to select fragment transition and remember the stack entry where it
+ * need pops to.
+ * </ul>
  * <h3>Theming and Stylists</h3>
  * <p>
  * GuidedStepFragment delegates its visual styling to classes called stylists. The {@link
@@ -106,8 +125,14 @@
  * <p>
  * <i>Note: Currently GuidedStepFragments grouped in this way must all be defined programmatically,
  * rather than in XML. This restriction may be removed in the future.</i>
- * <p>
+ *
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeight
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeightTwoPanels
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackgroundDark
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsElevation
  * @see GuidanceStylist
  * @see GuidanceStylist.Guidance
  * @see GuidedAction
@@ -118,24 +143,81 @@
 
     private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepFragment";
     private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
-    private static final String EXTRA_ACTION_ENTRY_TRANSITION_ENABLED = "entryTransitionEnabled";
-    private static final String EXTRA_ENTRY_TRANSITION_PERFORMED = "entryTransitionPerformed";
+
+    private static final String ENTRY_NAME_REPLACE = "GuidedStepDefault";
+
+    private static final String ENTRY_NAME_ENTRANCE = "GuidedStepEntrance";
+
+    /**
+     * Fragment argument name for UI style.  The argument value is persisted in fragment state.
+     * The value is initially {@link #UI_STYLE_ENTRANCE} and might be changed in one of the three
+     * helper functions:
+     * <ul>
+     * <li>{@link #addAsRoot(Activity, GuidedStepFragment, int)}</li>
+     * <li>{@link #add(FragmentManager, GuidedStepFragment)} or {@link #add(FragmentManager,
+     * GuidedStepFragment, int)}</li>
+     * </ul>
+     * <p>
+     * Argument value can be either:
+     * <ul>
+     * <li>{@link #UI_STYLE_REPLACE}</li>
+     * <li>{@link #UI_STYLE_ENTRANCE}</li>
+     * <li>{@link #UI_STYLE_ACTIVITY_ROOT}</li>
+     * </ul>
+     */
+    public static final String EXTRA_UI_STYLE = "uiStyle";
+
+    /**
+     * This is the case that we use GuidedStepFragment to replace another existing
+     * GuidedStepFragment when moving forward to next step. Default behavior of this style is:
+     * <ul>
+     * <li>Enter transition slides in from END(right), exit transition same as
+     * {@link #UI_STYLE_ENTRANCE}.
+     * </li>
+     * </ul>
+     */
+    public static final int UI_STYLE_REPLACE = 0;
+
+    /**
+     * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned in
+     * GuidedStepFragment constructor. This is the case that we show GuidedStepFragment on top of
+     * other content. The default behavior of this style:
+     * <ul>
+     * <li>Enter transition slides in from two sides, exit transition slide out to START(left).
+     * Background will be faded in. Note: Changing exit transition by UI style is not working
+     * because fragment transition asks for exit transition before UI style is restored in Fragment
+     * .onCreate().</li>
+     * </ul>
+     */
+    public static final int UI_STYLE_ENTRANCE = 1;
+
+    /**
+     * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
+     * GuidedStepFragment in a separate activity. The default behavior of this style:
+     * <ul>
+     * <li>Enter transition is assigned null (will rely on activity transition), exit transition is
+     * same as {@link #UI_STYLE_ENTRANCE}. Note: Changing exit transition by UI style is not working
+     * because fragment transition asks for exit transition before UI style is restored in
+     * Fragment.onCreate().</li>
+     * </ul>
+     */
+    public static final int UI_STYLE_ACTIVITY_ROOT = 2;
+
     private static final String TAG = "GuidedStepFragment";
-    private static final boolean DEBUG = true;
-    private static final int ANIMATION_FRAGMENT_ENTER = 1;
-    private static final int ANIMATION_FRAGMENT_EXIT = 2;
-    private static final int ANIMATION_FRAGMENT_ENTER_POP = 3;
-    private static final int ANIMATION_FRAGMENT_EXIT_POP = 4;
+    private static final boolean DEBUG = false;
 
     private int mTheme;
+    private ContextThemeWrapper mThemeWrapper;
     private GuidanceStylist mGuidanceStylist;
     private GuidedActionsStylist mActionsStylist;
+    private GuidedActionsStylist mButtonActionsStylist;
     private GuidedActionAdapter mAdapter;
-    private VerticalGridView mListView;
+    private GuidedActionAdapter mButtonAdapter;
+    private GuidedActionAdapterGroup mAdapterGroup;
     private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
+    private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
     private int mSelectedIndex = -1;
-    private boolean mEntryTransitionPerformed;
-    private boolean mEntryTransitionEnabled = true;
+    private int mButtonSelectedIndex = -1;
 
     public GuidedStepFragment() {
         // We need to supply the theme before any potential call to onInflate in order
@@ -143,6 +225,8 @@
         mTheme = onProvideTheme();
         mGuidanceStylist = onCreateGuidanceStylist();
         mActionsStylist = onCreateActionsStylist();
+        mButtonActionsStylist = onCreateButtonActionsStylist();
+        onProvideFragmentTransitions();
     }
 
     /**
@@ -164,6 +248,15 @@
     }
 
     /**
+     * Creates the presenter used to style a sided actions panel for button only.
+     * The default implementation returns a basic GuidedActionsStylist.
+     * @return The GuidedActionsStylist used in this fragment.
+     */
+    public GuidedActionsStylist onCreateButtonActionsStylist() {
+        return new GuidedActionsStylist();
+    }
+
+    /**
      * Returns the theme used for styling the fragment. The default returns -1, indicating that the
      * host Activity's theme should be used.
      * @return The theme resource ID of the theme to use in this fragment, or -1 to use the
@@ -195,6 +288,16 @@
     }
 
     /**
+     * Fills out the set of actions shown at right available to the user. This hook is called during
+     * {@link #onCreate}. The default leaves the list of actions empty; subclasses may override.
+     * @param actions A non-null, empty list ready to be populated.
+     * @param savedInstanceState The saved instance state from onCreate.
+     */
+    public void onCreateButtonActions(@NonNull List<GuidedAction> actions,
+            Bundle savedInstanceState) {
+    }
+
+    /**
      * Callback invoked when an action is taken by the user. Subclasses should override in
      * order to act on the user's decisions.
      * @param action The chosen action.
@@ -211,8 +314,34 @@
     }
 
     /**
+     * Callback invoked when an action's title or description has been edited.
+     * Override {@link #onGuidedActionEditedAndProceed(GuidedAction)} instead of app wants to
+     * control the next action to focus on.
+     */
+    public void onGuidedActionEdited(GuidedAction action) {
+    }
+
+    /**
+     * Callback invoked when an action's title or description has been edited.  Default
+     * implementation calls {@link #onGuidedActionEdited(GuidedAction)} and returns
+     * {@link GuidedAction#ACTION_ID_NEXT}.
+     *
+     * @param action The action that has been edited.
+     * @return ID of the action will be focused or {@link GuidedAction#ACTION_ID_NEXT},
+     * {@link GuidedAction#ACTION_ID_CURRENT}.
+     */
+    public long onGuidedActionEditedAndProceed(GuidedAction action) {
+        onGuidedActionEdited(action);
+        return GuidedAction.ACTION_ID_NEXT;
+    }
+
+    /**
      * Adds the specified GuidedStepFragment to the fragment stack, replacing any existing
-     * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom animations.
+     * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
+     * transitions.  A backstack entry is added, so the fragment will be dismissed when BACK key
+     * is pressed.
+     * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE}
+     * <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
      * <p>
      * Note: currently fragments added using this method must be created programmatically rather
      * than via XML.
@@ -224,19 +353,165 @@
         return add(fragmentManager, fragment, android.R.id.content);
     }
 
-    // Note, this method used to be public, but I haven't found a good way for a client
-    // to specify an id.
-    private static int add(FragmentManager fm, GuidedStepFragment f, int id) {
-        boolean inGuidedStep = getCurrentGuidedStepFragment(fm) != null;
-        FragmentTransaction ft = fm.beginTransaction();
+    /**
+     * Adds the specified GuidedStepFragment to the fragment stack, replacing any existing
+     * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
+     * transitions.  A backstack entry is added, so the fragment will be dismissed when BACK key
+     * is pressed.
+     * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE} and
+     * {@link #onAddSharedElementTransition(FragmentTransaction, GuidedStepFragment)} will be called
+     * to perform shared element transition between GuidedStepFragments.
+     * <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
+     * <p>
+     * Note: currently fragments added using this method must be created programmatically rather
+     * than via XML.
+     * @param fragmentManager The FragmentManager to be used in the transaction.
+     * @param fragment The GuidedStepFragment to be inserted into the fragment stack.
+     * @param id The id of container to add GuidedStepFragment, can be android.R.id.content.
+     * @return The ID returned by the call FragmentTransaction.replace.
+     */
+    public static int add(FragmentManager fragmentManager, GuidedStepFragment fragment, int id) {
+        GuidedStepFragment current = getCurrentGuidedStepFragment(fragmentManager);
+        boolean inGuidedStep = current != null;
+        FragmentTransaction ft = fragmentManager.beginTransaction();
 
-        if (inGuidedStep) {
-            ft.setCustomAnimations(ANIMATION_FRAGMENT_ENTER,
-                    ANIMATION_FRAGMENT_EXIT, ANIMATION_FRAGMENT_ENTER_POP,
-                    ANIMATION_FRAGMENT_EXIT_POP);
-            ft.addToBackStack(null);
+        fragment.setUiStyle(inGuidedStep ? UI_STYLE_REPLACE : UI_STYLE_ENTRANCE);
+        ft.addToBackStack(fragment.generateStackEntryName());
+        if (current != null) {
+            fragment.onAddSharedElementTransition(ft, current);
         }
-        return ft.replace(id, f, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+        return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+    }
+
+    /**
+     * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_REPLACE} (aka
+     * when the GuidedStepFragment replacing an existing GuidedStepFragment). Default implementation
+     * establishes connections between action background views to morph action background bounds
+     * change from disappearing GuidedStepFragment into this GuidedStepFragment. The default
+     * implementation heavily relies on {@link GuidedActionsStylist}'s layout, app may override this
+     * method when modifying the default layout of {@link GuidedActionsStylist}.
+     *
+     * @see GuidedActionsStylist
+     * @see #onProvideFragmentTransitions()
+     * @param ft The FragmentTransaction to add shared element.
+     * @param disappearing The disappearing fragment.
+     */
+    protected void onAddSharedElementTransition(FragmentTransaction ft, GuidedStepFragment
+            disappearing) {
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.action_fragment_root), "action_fragment_root");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.action_fragment_background), "action_fragment_background");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.action_fragment), "action_fragment");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_root), "guidedactions_root");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_selector), "guidedactions_selector");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_content), "guidedactions_content");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_list_background), "guidedactions_list_background");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_root2), "guidedactions_root2");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_selector2), "guidedactions_selector2");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_content2), "guidedactions_content2");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_list_background2), "guidedactions_list_background2");
+    }
+
+    /**
+     * Returns BackStackEntry name for the GuidedStepFragment or empty String if no entry is
+     * associated.  Note {@link #UI_STYLE_ACTIVITY_ROOT} will return empty String.  The method
+     * returns undefined value if the fragment is not in FragmentManager.
+     * @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
+     * associated.
+     */
+    public String generateStackEntryName() {
+        return generateStackEntryName(getUiStyle(), getClass());
+    }
+
+    /**
+     * Generates BackStackEntry name for GuidedStepFragment class or empty String if no entry is
+     * associated.  Note {@link #UI_STYLE_ACTIVITY_ROOT} is not allowed and returns empty String.
+     * @param uiStyle {@link #UI_STYLE_REPLACE} or {@link #UI_STYLE_ENTRANCE}
+     * @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
+     * associated.
+     */
+    public static String generateStackEntryName(int uiStyle, Class guidedStepFragmentClass) {
+        if (!GuidedStepFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+            return "";
+        }
+        switch (uiStyle) {
+        case UI_STYLE_REPLACE:
+            return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
+        case UI_STYLE_ENTRANCE:
+            return ENTRY_NAME_ENTRANCE + guidedStepFragmentClass.getName();
+        case UI_STYLE_ACTIVITY_ROOT:
+        default:
+            return "";
+        }
+    }
+
+    /**
+     * Returns true if the backstack represents GuidedStepFragment with {@link #UI_STYLE_ENTRANCE};
+     * false otherwise.
+     * @param backStackEntryName Name of BackStackEntry.
+     * @return True if the backstack represents GuidedStepFragment with {@link #UI_STYLE_ENTRANCE};
+     * false otherwise.
+     */
+    public static boolean isUiStyleEntrance(String backStackEntryName) {
+        return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE);
+    }
+
+    /**
+     * Returns true if the backstack represents GuidedStepFragment with {@link #UI_STYLE_REPLACE};
+     * false otherwise.
+     * @param backStackEntryName Name of BackStackEntry.
+     * @return True if the backstack represents GuidedStepFragment with {@link #UI_STYLE_REPLACE};
+     * false otherwise.
+     */
+    public static boolean isUiStyleDefault(String backStackEntryName) {
+        return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_REPLACE);
+    }
+
+    /**
+     * Extract Class name from BackStackEntry name.
+     * @param backStackEntryName Name of BackStackEntry.
+     * @return Class name of GuidedStepFragment.
+     */
+    public static String getGuidedStepFragmentClassName(String backStackEntryName) {
+        if (backStackEntryName.startsWith(ENTRY_NAME_REPLACE)) {
+            return backStackEntryName.substring(ENTRY_NAME_REPLACE.length());
+        } else if (backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE)) {
+            return backStackEntryName.substring(ENTRY_NAME_ENTRANCE.length());
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Adds the specified GuidedStepFragment as content of Activity; no backstack entry is added so
+     * the activity will be dismissed when BACK key is pressed.
+     * {@link #UI_STYLE_ACTIVITY_ROOT} is assigned.
+     *
+     * Note: currently fragments added using this method must be created programmatically rather
+     * than via XML.
+     * @param activity The Activity to be used to insert GuidedstepFragment.
+     * @param fragment The GuidedStepFragment to be inserted into the fragment stack.
+     * @param id The id of container to add GuidedStepFragment, can be android.R.id.content.
+     * @return The ID returned by the call FragmentTransaction.replace.
+     */
+    public static int addAsRoot(Activity activity, GuidedStepFragment fragment, int id) {
+        // Workaround b/23764120: call getDecorView() to force requestFeature of ActivityTransition.
+        activity.getWindow().getDecorView();
+
+        FragmentManager fragmentManager = activity.getFragmentManager();
+        FragmentTransaction ft = fragmentManager.beginTransaction();
+        fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
+        return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
     }
 
     /**
@@ -268,6 +543,99 @@
     }
 
     /**
+     * Returns the list of button GuidedActions that the user may take in this fragment.
+     * @return The list of button GuidedActions for this fragment.
+     */
+    public List<GuidedAction> getButtonActions() {
+        return mButtonActions;
+    }
+
+    /**
+     * Find button GuidedAction by Id.
+     * @param id  Id of the button action to search.
+     * @return  GuidedAction object or null if not found.
+     */
+    public GuidedAction findButtonActionById(long id) {
+        int index = findButtonActionPositionById(id);
+        return index >= 0 ? mButtonActions.get(index) : null;
+    }
+
+    /**
+     * Find button GuidedAction position in array by Id.
+     * @param id  Id of the button action to search.
+     * @return  position of GuidedAction object in array or -1 if not found.
+     */
+    public int findButtonActionPositionById(long id) {
+        if (mButtonActions != null) {
+            for (int i = 0; i < mButtonActions.size(); i++) {
+                GuidedAction action = mButtonActions.get(i);
+                if (mButtonActions.get(i).getId() == id) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the GuidedActionsStylist that displays the button actions the user may take.
+     * @return The GuidedActionsStylist for this fragment.
+     */
+    public GuidedActionsStylist getGuidedButtonActionsStylist() {
+        return mButtonActionsStylist;
+    }
+
+    /**
+     * Sets the list of button GuidedActions that the user may take in this fragment.
+     * @param actions The list of button GuidedActions for this fragment.
+     */
+    public void setButtonActions(List<GuidedAction> actions) {
+        mButtonActions = actions;
+        if (mButtonAdapter != null) {
+            mButtonAdapter.setActions(mButtonActions);
+        }
+    }
+
+    /**
+     * Notify an button action has changed and update its UI.
+     * @param position Position of the button GuidedAction in array.
+     */
+    public void notifyButtonActionChanged(int position) {
+        if (mButtonAdapter != null) {
+            mButtonAdapter.notifyItemChanged(position);
+        }
+    }
+
+    /**
+     * Returns the view corresponding to the button action at the indicated position in the list of
+     * actions for this fragment.
+     * @param position The integer position of the button action of interest.
+     * @return The View corresponding to the button action at the indicated position, or null if
+     * that action is not currently onscreen.
+     */
+    public View getButtonActionItemView(int position) {
+        final RecyclerView.ViewHolder holder = mButtonActionsStylist.getActionsGridView()
+                    .findViewHolderForPosition(position);
+        return holder == null ? null : holder.itemView;
+    }
+
+    /**
+     * Scrolls the action list to the position indicated, selecting that button action's view.
+     * @param position The integer position of the button action of interest.
+     */
+    public void setSelectedButtonActionPosition(int position) {
+        mButtonActionsStylist.getActionsGridView().setSelectedPosition(position);
+    }
+
+    /**
+     * Returns the position if the currently selected button GuidedAction.
+     * @return position The integer position of the currently selected button action.
+     */
+    public int getSelectedButtonActionPosition() {
+        return mButtonActionsStylist.getActionsGridView().getSelectedPosition();
+    }
+
+    /**
      * Returns the list of GuidedActions that the user may take in this fragment.
      * @return The list of GuidedActions for this fragment.
      */
@@ -276,6 +644,33 @@
     }
 
     /**
+     * Find GuidedAction by Id.
+     * @param id  Id of the action to search.
+     * @return  GuidedAction object or null if not found.
+     */
+    public GuidedAction findActionById(long id) {
+        int index = findActionPositionById(id);
+        return index >= 0 ? mActions.get(index) : null;
+    }
+
+    /**
+     * Find GuidedAction position in array by Id.
+     * @param id  Id of the action to search.
+     * @return  position of GuidedAction object in array or -1 if not found.
+     */
+    public int findActionPositionById(long id) {
+        if (mActions != null) {
+            for (int i = 0; i < mActions.size(); i++) {
+                GuidedAction action = mActions.get(i);
+                if (mActions.get(i).getId() == id) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
      * Sets the list of GuidedActions that the user may take in this fragment.
      * @param actions The list of GuidedActions for this fragment.
      */
@@ -287,6 +682,16 @@
     }
 
     /**
+     * Notify an action has changed and update its UI.
+     * @param position Position of the GuidedAction in array.
+     */
+    public void notifyActionChanged(int position) {
+        if (mAdapter != null) {
+            mAdapter.notifyItemChanged(position);
+        }
+    }
+
+    /**
      * Returns the view corresponding to the action at the indicated position in the list of
      * actions for this fragment.
      * @param position The integer position of the action of interest.
@@ -294,7 +699,9 @@
      * action is not currently onscreen.
      */
     public View getActionItemView(int position) {
-        return mListView.findViewHolderForPosition(position).itemView;
+        final RecyclerView.ViewHolder holder = mActionsStylist.getActionsGridView()
+                    .findViewHolderForPosition(position);
+        return holder == null ? null : holder.itemView;
     }
 
     /**
@@ -302,7 +709,7 @@
      * @param position The integer position of the action of interest.
      */
     public void setSelectedActionPosition(int position) {
-        mListView.setSelectedPosition(position);
+        mActionsStylist.getActionsGridView().setSelectedPosition(position);
     }
 
     /**
@@ -310,7 +717,126 @@
      * @return position The integer position of the currently selected action.
      */
     public int getSelectedActionPosition() {
-        return mListView.getSelectedPosition();
+        return mActionsStylist.getActionsGridView().getSelectedPosition();
+    }
+
+    /**
+     * Called by Constructor to provide fragment transitions.  The default implementation assigns
+     * transitions based on {@link #getUiStyle()}:
+     * <ul>
+     * <li> {@link #UI_STYLE_REPLACE} Slide from/to end(right) for enter transition, slide from/to
+     * start(left) for exit transition, shared element enter transition is set to ChangeBounds.
+     * <li> {@link #UI_STYLE_ENTRANCE} Enter transition is set to slide from both sides, exit
+     * transition is same as {@link #UI_STYLE_REPLACE}, no shared element enter transition.
+     * <li> {@link #UI_STYLE_ACTIVITY_ROOT} Enter transition is set to null and app should rely on
+     * activity transition, exit transition is same as {@link #UI_STYLE_REPLACE}, no shared element
+     * enter transition.
+     * </ul>
+     * <p>
+     * The default implementation heavily relies on {@link GuidedActionsStylist} and
+     * {@link GuidanceStylist} layout, app may override this method when modifying the default
+     * layout of {@link GuidedActionsStylist} or {@link GuidanceStylist}.
+     * <p>
+     * TIP: because the fragment view is removed during fragment transition, in general app cannot
+     * use two Visibility transition together. Workaround is to create your own Visibility
+     * transition that controls multiple animators (e.g. slide and fade animation in one Transition
+     * class).
+     */
+    protected void onProvideFragmentTransitions() {
+        if (Build.VERSION.SDK_INT >= 21) {
+            final int uiStyle = getUiStyle();
+            if (uiStyle == UI_STYLE_REPLACE) {
+                Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END);
+                TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
+                TransitionHelper.setEnterTransition(this, enterTransition);
+
+                Object changeBounds = TransitionHelper.createChangeBounds(false);
+                TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
+            } else if (uiStyle == UI_STYLE_ENTRANCE) {
+                Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
+                        TransitionHelper.FADE_OUT);
+                TransitionHelper.include(fade, R.id.guidedstep_background);
+                Object slide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
+                        Gravity.START);
+                TransitionHelper.include(slide, R.id.content_fragment);
+                TransitionHelper.include(slide, R.id.action_fragment_root);
+                Object enterTransition = TransitionHelper.createTransitionSet(false);
+                TransitionHelper.addTransition(enterTransition, fade);
+                TransitionHelper.addTransition(enterTransition, slide);
+                TransitionHelper.setEnterTransition(this, enterTransition);
+
+                // No shared element transition
+                TransitionHelper.setSharedElementEnterTransition(this, null);
+            } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
+                // for Activity root, we dont need enter transition, use activity transition
+                TransitionHelper.setEnterTransition(this, null);
+                // No shared element transition
+                TransitionHelper.setSharedElementEnterTransition(this, null);
+            }
+            // exitTransition is same for all style
+            Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
+            TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
+            TransitionHelper.setExitTransition(this, exitTransition);
+        }
+    }
+
+    /**
+     * Called by onCreateView to inflate background view.  Default implementation loads view
+     * from {@link R.layout#lb_guidedstep_background} which holds a reference to
+     * guidedStepBackground.
+     * @param inflater LayoutInflater to load background view.
+     * @param container Parent view of background view.
+     * @param savedInstanceState
+     * @return Created background view or null if no background.
+     */
+    public View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
+    }
+
+    /**
+     * Set UI style to fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when fragment
+     * is first initialized. UI style is used to choose different fragment transition animations and
+     * determine if this is the first GuidedStepFragment on backstack. In most cases app does not
+     * directly call this method, app calls helper function
+     * {@link #add(FragmentManager, GuidedStepFragment, int)}. However if the app creates Fragment
+     * transaction and controls backstack by itself, it would need call setUiStyle() to select the
+     * fragment transition to use.
+     *
+     * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+     *        {@link #UI_STYLE_ENTRANCE}.
+     */
+    public void setUiStyle(int style) {
+        int oldStyle = getUiStyle();
+        Bundle arguments = getArguments();
+        boolean isNew = false;
+        if (arguments == null) {
+            arguments = new Bundle();
+            isNew = true;
+        }
+        arguments.putInt(EXTRA_UI_STYLE, style);
+        // call setArgument() will validate if the fragment is already added.
+        if (isNew) {
+            setArguments(arguments);
+        }
+        if (style != oldStyle) {
+            onProvideFragmentTransitions();
+        }
+    }
+
+    /**
+     * Read UI style from fragment arguments.  Default value is {@link #UI_STYLE_ENTRANCE} when
+     * fragment is first initialized.  UI style is used to choose different fragment transition
+     * animations and determine if this is the first GuidedStepFragment on backstack.
+     *
+     * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+     * {@link #UI_STYLE_ENTRANCE}.
+     * @see #onProvideFragmentTransitions()
+     */
+    public int getUiStyle() {
+        Bundle b = getArguments();
+        if (b == null) return UI_STYLE_ENTRANCE;
+        return b.getInt(EXTRA_UI_STYLE, UI_STYLE_ENTRANCE);
     }
 
     /**
@@ -320,16 +846,34 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         if (DEBUG) Log.v(TAG, "onCreate");
+        // Set correct transition from saved arguments.
+        onProvideFragmentTransitions();
         Bundle state = (savedInstanceState != null) ? savedInstanceState : getArguments();
         if (state != null) {
             if (mSelectedIndex == -1) {
                 mSelectedIndex = state.getInt(EXTRA_ACTION_SELECTED_INDEX, -1);
             }
-            mEntryTransitionEnabled = state.getBoolean(EXTRA_ACTION_ENTRY_TRANSITION_ENABLED, true);
-            mEntryTransitionPerformed = state.getBoolean(EXTRA_ENTRY_TRANSITION_PERFORMED, false);
         }
-        mActions.clear();
-        onCreateActions(mActions, savedInstanceState);
+        ArrayList<GuidedAction> actions = new ArrayList<GuidedAction>();
+        onCreateActions(actions, savedInstanceState);
+        setActions(actions);
+        ArrayList<GuidedAction> buttonActions = new ArrayList<GuidedAction>();
+        onCreateButtonActions(buttonActions, savedInstanceState);
+        setButtonActions(buttonActions);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDestroyView() {
+        mGuidanceStylist.onDestroyView();
+        mActionsStylist.onDestroyView();
+        mButtonActionsStylist.onDestroyView();
+        mAdapter = null;
+        mButtonAdapter = null;
+        mAdapterGroup = null;
+        super.onDestroyView();
     }
 
     /**
@@ -343,9 +887,10 @@
         resolveTheme();
         inflater = getThemeInflater(inflater);
 
-        View v = inflater.inflate(R.layout.lb_guidedstep_fragment, container, false);
-        ViewGroup guidanceContainer = (ViewGroup) v.findViewById(R.id.content_fragment);
-        ViewGroup actionContainer = (ViewGroup) v.findViewById(R.id.action_fragment);
+        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_guidedstep_fragment,
+                container, false);
+        ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
+        ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
 
         Guidance guidance = onCreateGuidance(savedInstanceState);
         View guidanceView = mGuidanceStylist.onCreateView(inflater, guidanceContainer, guidance);
@@ -354,15 +899,77 @@
         View actionsView = mActionsStylist.onCreateView(inflater, actionContainer);
         actionContainer.addView(actionsView);
 
-        mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+        View buttonActionsView = mButtonActionsStylist.onCreateView(inflater, actionContainer);
+        mButtonActionsStylist.setAsButtonActions();
+        actionContainer.addView(buttonActionsView);
 
-        mListView = mActionsStylist.getActionsGridView();
-        mListView.setAdapter(mAdapter);
+        GuidedActionAdapter.EditListener editListener = new GuidedActionAdapter.EditListener() {
+
+                @Override
+                public void onImeOpen() {
+                    runImeAnimations(true);
+                }
+
+                @Override
+                public void onImeClose() {
+                    runImeAnimations(false);
+                }
+
+                @Override
+                public long onGuidedActionEdited(GuidedAction action) {
+                    return GuidedStepFragment.this.onGuidedActionEditedAndProceed(action);
+                }
+        };
+
+        mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+        mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, mButtonActionsStylist);
+        mAdapterGroup = new GuidedActionAdapterGroup();
+        mAdapterGroup.addAdpter(mAdapter);
+        mAdapterGroup.addAdpter(mButtonAdapter);
+        mAdapterGroup.setEditListener(editListener);
+
+        mActionsStylist.getActionsGridView().setAdapter(mAdapter);
+        mButtonActionsStylist.getActionsGridView().setAdapter(mButtonAdapter);
+        if (mButtonActions.size() == 0) {
+            // when there is no button actions, we dont need show the second panel, but keep
+            // the width zero to run ChangeBounds transition.
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+                    buttonActionsView.getLayoutParams();
+            lp.weight = 0;
+            buttonActionsView.setLayoutParams(lp);
+        } else {
+            // when there are two actions panel, we need adjust the weight of action to
+            // guidedActionContentWidthWeightTwoPanels.
+            Context ctx = mThemeWrapper != null ? mThemeWrapper : getActivity();
+            TypedValue typedValue = new TypedValue();
+            if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
+                    typedValue, true)) {
+                View actionsRoot = root.findViewById(R.id.action_fragment_root);
+                float weight = typedValue.getFloat();
+                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionsRoot
+                        .getLayoutParams();
+                lp.weight = weight;
+                actionsRoot.setLayoutParams(lp);
+            }
+        }
+
         int pos = (mSelectedIndex >= 0 && mSelectedIndex < mActions.size()) ?
                 mSelectedIndex : getFirstCheckedAction();
-        mListView.setSelectedPosition(pos);
+        setSelectedActionPosition(pos);
 
-        return v;
+        setSelectedButtonActionPosition(0);
+
+        View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
+        if (backgroundView != null) {
+            root.addView(backgroundView, 0);
+        }
+        return root;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mActionsStylist.getActionsGridView().requestFocus();
     }
 
     /**
@@ -372,75 +979,11 @@
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         outState.putInt(EXTRA_ACTION_SELECTED_INDEX,
-                (mListView != null) ? getSelectedActionPosition() : mSelectedIndex);
-        outState.putBoolean(EXTRA_ACTION_ENTRY_TRANSITION_ENABLED, mEntryTransitionEnabled);
-        outState.putBoolean(EXTRA_ENTRY_TRANSITION_PERFORMED, mEntryTransitionPerformed);
+                (mActionsStylist.getActionsGridView() != null) ?
+                        getSelectedActionPosition() : mSelectedIndex);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onStart() {
-        if (DEBUG) Log.v(TAG, "onStart");
-        super.onStart();
-        if (isEntryTransitionEnabled() && !mEntryTransitionPerformed) {
-            mEntryTransitionPerformed = true;
-            performEntryTransition();
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
-        if (DEBUG) Log.v(TAG, "onCreateAnimator: " + transit + " " + enter + " " + nextAnim);
-        View mainView = getView();
-
-        ArrayList<Animator> animators = new ArrayList<Animator>();
-        switch (nextAnim) {
-            case ANIMATION_FRAGMENT_ENTER:
-                mGuidanceStylist.onFragmentEnter(animators);
-                mActionsStylist.onFragmentEnter(animators);
-                break;
-            case ANIMATION_FRAGMENT_EXIT:
-                mGuidanceStylist.onFragmentExit(animators);
-                mActionsStylist.onFragmentExit(animators);
-                break;
-            case ANIMATION_FRAGMENT_ENTER_POP:
-                mGuidanceStylist.onFragmentReenter(animators);
-                mActionsStylist.onFragmentReenter(animators);
-                break;
-            case ANIMATION_FRAGMENT_EXIT_POP:
-                mGuidanceStylist.onFragmentReturn(animators);
-                mActionsStylist.onFragmentReturn(animators);
-                break;
-            default:
-                return super.onCreateAnimator(transit, enter, nextAnim);
-        }
-
-        mEntryTransitionPerformed = true;
-        return createDummyAnimator(mainView, animators);
-    }
-
-    /**
-     * Returns whether entry transitions are enabled for this fragment.
-     * @return Whether entry transitions are enabled for this fragment.
-     */
-    protected boolean isEntryTransitionEnabled() {
-        return mEntryTransitionEnabled;
-    }
-
-    /**
-     * Sets whether entry transitions are enabled for this fragment.
-     * @param enabled Whether to enable entry transitions for this fragment.
-     */
-    protected void setEntryTransitionEnabled(boolean enabled) {
-        mEntryTransitionEnabled = enabled;
-    }
-
-    private boolean isGuidedStepTheme(Context context) {
+    private static boolean isGuidedStepTheme(Context context) {
         int resId = R.attr.guidedStepThemeFlag;
         TypedValue typedValue = new TypedValue();
         boolean found = context.getTheme().resolveAttribute(resId, typedValue, true);
@@ -448,8 +991,58 @@
         return found && typedValue.type == TypedValue.TYPE_INT_BOOLEAN && typedValue.data != 0;
     }
 
+    /**
+     * Convenient method to close GuidedStepFragments on top of other content or finish Activity if
+     * GuidedStepFragments were started in a separate activity.  Pops all stack entries including
+     * {@link #UI_STYLE_ENTRANCE}; if {@link #UI_STYLE_ENTRANCE} is not found, finish the activity.
+     * Note that this method must be paired with {@link #add(FragmentManager, GuidedStepFragment,
+     * int)} which sets up the stack entry name for finding which fragment we need to pop back to.
+     */
+    public void finishGuidedStepFragments() {
+        final FragmentManager fragmentManager = getFragmentManager();
+        final int entryCount = fragmentManager.getBackStackEntryCount();
+        if (entryCount > 0) {
+            for (int i = entryCount - 1; i >= 0; i--) {
+                BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+                if (isUiStyleEntrance(entry.getName())) {
+                    GuidedStepFragment top = getCurrentGuidedStepFragment(fragmentManager);
+                    if (top != null) {
+                        top.setUiStyle(UI_STYLE_ENTRANCE);
+                    }
+                    fragmentManager.popBackStack(entry.getId(),
+                            FragmentManager.POP_BACK_STACK_INCLUSIVE);
+                    return;
+                }
+            }
+        }
+        ActivityCompat.finishAfterTransition(getActivity());
+    }
+
+    /**
+     * Convenient method to pop to fragment with Given class.
+     * @param  guidedStepFragmentClass  Name of the Class of GuidedStepFragment to pop to.
+     * @param flags Either 0 or {@link FragmentManager#POP_BACK_STACK_INCLUSIVE}.
+     */
+    public void popBackStackToGuidedStepFragment(Class guidedStepFragmentClass, int flags) {
+        if (!GuidedStepFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+            return;
+        }
+        final FragmentManager fragmentManager = getFragmentManager();
+        final int entryCount = fragmentManager.getBackStackEntryCount();
+        String className = guidedStepFragmentClass.getName();
+        if (entryCount > 0) {
+            for (int i = entryCount - 1; i >= 0; i--) {
+                BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+                String entryClassName = getGuidedStepFragmentClassName(entry.getName());
+                if (className.equals(entryClassName)) {
+                    fragmentManager.popBackStack(entry.getId(), flags);
+                    return;
+                }
+            }
+        }
+    }
+
     private void resolveTheme() {
-        boolean hasThemeReference = true;
         // Look up the guidedStepTheme in the currently specified theme.  If it exists,
         // replace the theme with its value.
         Activity activity = getActivity();
@@ -461,15 +1054,21 @@
             boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
             if (DEBUG) Log.v(TAG, "Found guided step theme reference? " + found);
             if (found) {
-                if (isGuidedStepTheme(new ContextThemeWrapper(activity, typedValue.resourceId))) {
+                ContextThemeWrapper themeWrapper =
+                        new ContextThemeWrapper(activity, typedValue.resourceId);
+                if (isGuidedStepTheme(themeWrapper)) {
                     mTheme = typedValue.resourceId;
+                    mThemeWrapper = themeWrapper;
                 } else {
                     found = false;
+                    mThemeWrapper = null;
                 }
             }
             if (!found) {
                 Log.e(TAG, "GuidedStepFragment does not have an appropriate theme set.");
             }
+        } else if (mTheme != -1) {
+            mThemeWrapper = new ContextThemeWrapper(activity, mTheme);
         }
     }
 
@@ -477,8 +1076,7 @@
         if (mTheme == -1) {
             return inflater;
         } else {
-            Context ctw = new ContextThemeWrapper(getActivity(), mTheme);
-            return inflater.cloneInContext(ctw);
+            return inflater.cloneInContext(mThemeWrapper);
         }
     }
 
@@ -491,41 +1089,20 @@
         return 0;
     }
 
-    private void performEntryTransition() {
-        if (DEBUG) Log.v(TAG, "performEntryTransition");
-        final View mainView = getView();
-
-        mainView.setVisibility(View.INVISIBLE);
-
+    private void runImeAnimations(boolean entering) {
         ArrayList<Animator> animators = new ArrayList<Animator>();
-        mGuidanceStylist.onActivityEnter(animators);
-        mActionsStylist.onActivityEnter(animators);
-
-        final Animator animator = createDummyAnimator(mainView, animators);
-
-        // We need to defer the animation until the first layout has occurred, as we don't yet
-        // know the final locations of views.
-        mainView.getViewTreeObserver().addOnGlobalLayoutListener(
-                new ViewTreeObserver.OnGlobalLayoutListener() {
-                    @Override
-                    public void onGlobalLayout() {
-                        mainView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                        if (!isAdded()) {
-                            // We have been detached before this could run,
-                            // so just bail
-                            return;
-                        }
-
-                        mainView.setVisibility(View.VISIBLE);
-                        animator.start();
-                    }
-                });
-    }
-
-    private Animator createDummyAnimator(final View v, ArrayList<Animator> animators) {
-        final AnimatorSet animatorSet = new AnimatorSet();
-        animatorSet.playTogether(animators);
-        return new UntargetableAnimatorSet(animatorSet);
+        if (entering) {
+            mGuidanceStylist.onImeAppearing(animators);
+            mActionsStylist.onImeAppearing(animators);
+            mButtonActionsStylist.onImeAppearing(animators);
+        } else {
+            mGuidanceStylist.onImeDisappearing(animators);
+            mActionsStylist.onImeDisappearing(animators);
+            mButtonActionsStylist.onImeDisappearing(animators);
+        }
+        AnimatorSet set = new AnimatorSet();
+        set.playTogether(animators);
+        set.start();
     }
 
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
new file mode 100644
index 0000000..ad186ff
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -0,0 +1,1110 @@
+/* This file is auto-generated from GuidedStepFragment.java.  DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentManager.BackStackEntry;
+import android.support.v4.app.FragmentTransaction;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A GuidedStepSupportFragment is used to guide the user through a decision or series of decisions.
+ * It is composed of a guidance view on the left and a view on the right containing a list of
+ * possible actions.
+ * <p>
+ * <h3>Basic Usage</h3>
+ * <p>
+ * Clients of GuidedStepSupportFragment must create a custom subclass to attach to their Activities.
+ * This custom subclass provides the information necessary to construct the user interface and
+ * respond to user actions. At a minimum, subclasses should override:
+ * <ul>
+ * <li>{@link #onCreateGuidance}, to provide instructions to the user</li>
+ * <li>{@link #onCreateActions}, to provide a set of {@link GuidedAction}s the user can take</li>
+ * <li>{@link #onGuidedActionClicked}, to respond to those actions</li>
+ * </ul>
+ * <p>
+ * Clients use following helper functions to add GuidedStepSupportFragment to Activity or FragmentManager:
+ * <ul>
+ * <li>{@link #addAsRoot(FragmentActivity, GuidedStepSupportFragment, int)}, to be called during Activity onCreate,
+ * adds GuidedStepSupportFragment as the first Fragment in activity.</li>
+ * <li>{@link #add(FragmentManager, GuidedStepSupportFragment)} or {@link #add(FragmentManager,
+ * GuidedStepSupportFragment, int)}, to add GuidedStepSupportFragment on top of existing Fragments or
+ * replacing existing GuidedStepSupportFragment when moving forward to next step.</li>
+ * <li>{@link #finishGuidedStepSupportFragments()} can either finish the activity or pop all
+ * GuidedStepSupportFragment from stack.
+ * <li>If app chooses not to use the helper function, it is the app's responsibility to call
+ * {@link #setUiStyle(int)} to select fragment transition and remember the stack entry where it
+ * need pops to.
+ * </ul>
+ * <h3>Theming and Stylists</h3>
+ * <p>
+ * GuidedStepSupportFragment delegates its visual styling to classes called stylists. The {@link
+ * GuidanceStylist} is responsible for the left guidance view, while the {@link
+ * GuidedActionsStylist} is responsible for the right actions view. The stylists use theme
+ * attributes to derive values associated with the presentation, such as colors, animations, etc.
+ * Most simple visual aspects of GuidanceStylist and GuidedActionsStylist can be customized
+ * via theming; see their documentation for more information.
+ * <p>
+ * GuidedStepSupportFragments must have access to an appropriate theme in order for the stylists to
+ * function properly.  Specifically, the fragment must receive {@link
+ * android.support.v17.leanback.R.style#Theme_Leanback_GuidedStep}, or a theme whose parent is
+ * is set to that theme. Themes can be provided in one of three ways:
+ * <ul>
+ * <li>The simplest way is to set the theme for the host Activity to the GuidedStep theme or a
+ * theme that derives from it.</li>
+ * <li>If the Activity already has a theme and setting its parent theme is inconvenient, the
+ * existing Activity theme can have an entry added for the attribute {@link
+ * android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme}. If present,
+ * this theme will be used by GuidedStepSupportFragment as an overlay to the Activity's theme.</li>
+ * <li>Finally, custom subclasses of GuidedStepSupportFragment may provide a theme through the {@link
+ * #onProvideTheme} method. This can be useful if a subclass is used across multiple
+ * Activities.</li>
+ * </ul>
+ * <p>
+ * If the theme is provided in multiple ways, the onProvideTheme override has priority, followed by
+ * the Activty's theme.  (Themes whose parent theme is already set to the guided step theme do not
+ * need to set the guidedStepTheme attribute; if set, it will be ignored.)
+ * <p>
+ * If themes do not provide enough customizability, the stylists themselves may be subclassed and
+ * provided to the GuidedStepSupportFragment through the {@link #onCreateGuidanceStylist} and {@link
+ * #onCreateActionsStylist} methods.  The stylists have simple hooks so that subclasses
+ * may override layout files; subclasses may also have more complex logic to determine styling.
+ * <p>
+ * <h3>Guided sequences</h3>
+ * <p>
+ * GuidedStepSupportFragments can be grouped together to provide a guided sequence. GuidedStepSupportFragments
+ * grouped as a sequence use custom animations provided by {@link GuidanceStylist} and
+ * {@link GuidedActionsStylist} (or subclasses) during transitions between steps. Clients
+ * should use {@link #add} to place subsequent GuidedFragments onto the fragment stack so that
+ * custom animations are properly configured. (Custom animations are triggered automatically when
+ * the fragment stack is subsequently popped by any normal mechanism.)
+ * <p>
+ * <i>Note: Currently GuidedStepSupportFragments grouped in this way must all be defined programmatically,
+ * rather than in XML. This restriction may be removed in the future.</i>
+ *
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeight
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeightTwoPanels
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackgroundDark
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsElevation
+ * @see GuidanceStylist
+ * @see GuidanceStylist.Guidance
+ * @see GuidedAction
+ * @see GuidedActionsStylist
+ */
+public class GuidedStepSupportFragment extends Fragment implements GuidedActionAdapter.ClickListener,
+        GuidedActionAdapter.FocusListener {
+
+    private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepSupportFragment";
+    private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
+
+    private static final String ENTRY_NAME_REPLACE = "GuidedStepDefault";
+
+    private static final String ENTRY_NAME_ENTRANCE = "GuidedStepEntrance";
+
+    /**
+     * Fragment argument name for UI style.  The argument value is persisted in fragment state.
+     * The value is initially {@link #UI_STYLE_ENTRANCE} and might be changed in one of the three
+     * helper functions:
+     * <ul>
+     * <li>{@link #addAsRoot(FragmentActivity, GuidedStepSupportFragment, int)}</li>
+     * <li>{@link #add(FragmentManager, GuidedStepSupportFragment)} or {@link #add(FragmentManager,
+     * GuidedStepSupportFragment, int)}</li>
+     * </ul>
+     * <p>
+     * Argument value can be either:
+     * <ul>
+     * <li>{@link #UI_STYLE_REPLACE}</li>
+     * <li>{@link #UI_STYLE_ENTRANCE}</li>
+     * <li>{@link #UI_STYLE_ACTIVITY_ROOT}</li>
+     * </ul>
+     */
+    public static final String EXTRA_UI_STYLE = "uiStyle";
+
+    /**
+     * This is the case that we use GuidedStepSupportFragment to replace another existing
+     * GuidedStepSupportFragment when moving forward to next step. Default behavior of this style is:
+     * <ul>
+     * <li>Enter transition slides in from END(right), exit transition same as
+     * {@link #UI_STYLE_ENTRANCE}.
+     * </li>
+     * </ul>
+     */
+    public static final int UI_STYLE_REPLACE = 0;
+
+    /**
+     * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned in
+     * GuidedStepSupportFragment constructor. This is the case that we show GuidedStepSupportFragment on top of
+     * other content. The default behavior of this style:
+     * <ul>
+     * <li>Enter transition slides in from two sides, exit transition slide out to START(left).
+     * Background will be faded in. Note: Changing exit transition by UI style is not working
+     * because fragment transition asks for exit transition before UI style is restored in Fragment
+     * .onCreate().</li>
+     * </ul>
+     */
+    public static final int UI_STYLE_ENTRANCE = 1;
+
+    /**
+     * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
+     * GuidedStepSupportFragment in a separate activity. The default behavior of this style:
+     * <ul>
+     * <li>Enter transition is assigned null (will rely on activity transition), exit transition is
+     * same as {@link #UI_STYLE_ENTRANCE}. Note: Changing exit transition by UI style is not working
+     * because fragment transition asks for exit transition before UI style is restored in
+     * Fragment.onCreate().</li>
+     * </ul>
+     */
+    public static final int UI_STYLE_ACTIVITY_ROOT = 2;
+
+    private static final String TAG = "GuidedStepSupportFragment";
+    private static final boolean DEBUG = false;
+
+    private int mTheme;
+    private ContextThemeWrapper mThemeWrapper;
+    private GuidanceStylist mGuidanceStylist;
+    private GuidedActionsStylist mActionsStylist;
+    private GuidedActionsStylist mButtonActionsStylist;
+    private GuidedActionAdapter mAdapter;
+    private GuidedActionAdapter mButtonAdapter;
+    private GuidedActionAdapterGroup mAdapterGroup;
+    private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
+    private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
+    private int mSelectedIndex = -1;
+    private int mButtonSelectedIndex = -1;
+
+    public GuidedStepSupportFragment() {
+        // We need to supply the theme before any potential call to onInflate in order
+        // for the defaulting to work properly.
+        mTheme = onProvideTheme();
+        mGuidanceStylist = onCreateGuidanceStylist();
+        mActionsStylist = onCreateActionsStylist();
+        mButtonActionsStylist = onCreateButtonActionsStylist();
+        onProvideFragmentTransitions();
+    }
+
+    /**
+     * Creates the presenter used to style the guidance panel. The default implementation returns
+     * a basic GuidanceStylist.
+     * @return The GuidanceStylist used in this fragment.
+     */
+    public GuidanceStylist onCreateGuidanceStylist() {
+        return new GuidanceStylist();
+    }
+
+    /**
+     * Creates the presenter used to style the guided actions panel. The default implementation
+     * returns a basic GuidedActionsStylist.
+     * @return The GuidedActionsStylist used in this fragment.
+     */
+    public GuidedActionsStylist onCreateActionsStylist() {
+        return new GuidedActionsStylist();
+    }
+
+    /**
+     * Creates the presenter used to style a sided actions panel for button only.
+     * The default implementation returns a basic GuidedActionsStylist.
+     * @return The GuidedActionsStylist used in this fragment.
+     */
+    public GuidedActionsStylist onCreateButtonActionsStylist() {
+        return new GuidedActionsStylist();
+    }
+
+    /**
+     * Returns the theme used for styling the fragment. The default returns -1, indicating that the
+     * host Activity's theme should be used.
+     * @return The theme resource ID of the theme to use in this fragment, or -1 to use the
+     * host Activity's theme.
+     */
+    public int onProvideTheme() {
+        return -1;
+    }
+
+    /**
+     * Returns the information required to provide guidance to the user. This hook is called during
+     * {@link #onCreateView}.  May be overridden to return a custom subclass of {@link
+     * GuidanceStylist.Guidance} for use in a subclass of {@link GuidanceStylist}. The default
+     * returns a Guidance object with empty fields; subclasses should override.
+     * @param savedInstanceState The saved instance state from onCreateView.
+     * @return The Guidance object representing the information used to guide the user.
+     */
+    public @NonNull Guidance onCreateGuidance(Bundle savedInstanceState) {
+        return new Guidance("", "", "", null);
+    }
+
+    /**
+     * Fills out the set of actions available to the user. This hook is called during {@link
+     * #onCreate}. The default leaves the list of actions empty; subclasses should override.
+     * @param actions A non-null, empty list ready to be populated.
+     * @param savedInstanceState The saved instance state from onCreate.
+     */
+    public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+    }
+
+    /**
+     * Fills out the set of actions shown at right available to the user. This hook is called during
+     * {@link #onCreate}. The default leaves the list of actions empty; subclasses may override.
+     * @param actions A non-null, empty list ready to be populated.
+     * @param savedInstanceState The saved instance state from onCreate.
+     */
+    public void onCreateButtonActions(@NonNull List<GuidedAction> actions,
+            Bundle savedInstanceState) {
+    }
+
+    /**
+     * Callback invoked when an action is taken by the user. Subclasses should override in
+     * order to act on the user's decisions.
+     * @param action The chosen action.
+     */
+    @Override
+    public void onGuidedActionClicked(GuidedAction action) {
+    }
+
+    /**
+     * Callback invoked when an action is focused (made to be the current selection) by the user.
+     */
+    @Override
+    public void onGuidedActionFocused(GuidedAction action) {
+    }
+
+    /**
+     * Callback invoked when an action's title or description has been edited.
+     * Override {@link #onGuidedActionEditedAndProceed(GuidedAction)} instead of app wants to
+     * control the next action to focus on.
+     */
+    public void onGuidedActionEdited(GuidedAction action) {
+    }
+
+    /**
+     * Callback invoked when an action's title or description has been edited.  Default
+     * implementation calls {@link #onGuidedActionEdited(GuidedAction)} and returns
+     * {@link GuidedAction#ACTION_ID_NEXT}.
+     *
+     * @param action The action that has been edited.
+     * @return ID of the action will be focused or {@link GuidedAction#ACTION_ID_NEXT},
+     * {@link GuidedAction#ACTION_ID_CURRENT}.
+     */
+    public long onGuidedActionEditedAndProceed(GuidedAction action) {
+        onGuidedActionEdited(action);
+        return GuidedAction.ACTION_ID_NEXT;
+    }
+
+    /**
+     * Adds the specified GuidedStepSupportFragment to the fragment stack, replacing any existing
+     * GuidedStepSupportFragments in the stack, and configuring the fragment-to-fragment custom
+     * transitions.  A backstack entry is added, so the fragment will be dismissed when BACK key
+     * is pressed.
+     * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_REPLACE}
+     * <li>If current fragment on stack is not GuidedStepSupportFragment: assign {@link #UI_STYLE_ENTRANCE}
+     * <p>
+     * Note: currently fragments added using this method must be created programmatically rather
+     * than via XML.
+     * @param fragmentManager The FragmentManager to be used in the transaction.
+     * @param fragment The GuidedStepSupportFragment to be inserted into the fragment stack.
+     * @return The ID returned by the call FragmentTransaction.replace.
+     */
+    public static int add(FragmentManager fragmentManager, GuidedStepSupportFragment fragment) {
+        return add(fragmentManager, fragment, android.R.id.content);
+    }
+
+    /**
+     * Adds the specified GuidedStepSupportFragment to the fragment stack, replacing any existing
+     * GuidedStepSupportFragments in the stack, and configuring the fragment-to-fragment custom
+     * transitions.  A backstack entry is added, so the fragment will be dismissed when BACK key
+     * is pressed.
+     * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_REPLACE} and
+     * {@link #onAddSharedElementTransition(FragmentTransaction, GuidedStepSupportFragment)} will be called
+     * to perform shared element transition between GuidedStepSupportFragments.
+     * <li>If current fragment on stack is not GuidedStepSupportFragment: assign {@link #UI_STYLE_ENTRANCE}
+     * <p>
+     * Note: currently fragments added using this method must be created programmatically rather
+     * than via XML.
+     * @param fragmentManager The FragmentManager to be used in the transaction.
+     * @param fragment The GuidedStepSupportFragment to be inserted into the fragment stack.
+     * @param id The id of container to add GuidedStepSupportFragment, can be android.R.id.content.
+     * @return The ID returned by the call FragmentTransaction.replace.
+     */
+    public static int add(FragmentManager fragmentManager, GuidedStepSupportFragment fragment, int id) {
+        GuidedStepSupportFragment current = getCurrentGuidedStepSupportFragment(fragmentManager);
+        boolean inGuidedStep = current != null;
+        FragmentTransaction ft = fragmentManager.beginTransaction();
+
+        fragment.setUiStyle(inGuidedStep ? UI_STYLE_REPLACE : UI_STYLE_ENTRANCE);
+        ft.addToBackStack(fragment.generateStackEntryName());
+        if (current != null) {
+            fragment.onAddSharedElementTransition(ft, current);
+        }
+        return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+    }
+
+    /**
+     * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_REPLACE} (aka
+     * when the GuidedStepSupportFragment replacing an existing GuidedStepSupportFragment). Default implementation
+     * establishes connections between action background views to morph action background bounds
+     * change from disappearing GuidedStepSupportFragment into this GuidedStepSupportFragment. The default
+     * implementation heavily relies on {@link GuidedActionsStylist}'s layout, app may override this
+     * method when modifying the default layout of {@link GuidedActionsStylist}.
+     *
+     * @see GuidedActionsStylist
+     * @see #onProvideFragmentTransitions()
+     * @param ft The FragmentTransaction to add shared element.
+     * @param disappearing The disappearing fragment.
+     */
+    protected void onAddSharedElementTransition(FragmentTransaction ft, GuidedStepSupportFragment
+            disappearing) {
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.action_fragment_root), "action_fragment_root");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.action_fragment_background), "action_fragment_background");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.action_fragment), "action_fragment");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_root), "guidedactions_root");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_selector), "guidedactions_selector");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_content), "guidedactions_content");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_list_background), "guidedactions_list_background");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_root2), "guidedactions_root2");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_selector2), "guidedactions_selector2");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_content2), "guidedactions_content2");
+        TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+                R.id.guidedactions_list_background2), "guidedactions_list_background2");
+    }
+
+    /**
+     * Returns BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
+     * associated.  Note {@link #UI_STYLE_ACTIVITY_ROOT} will return empty String.  The method
+     * returns undefined value if the fragment is not in FragmentManager.
+     * @return BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
+     * associated.
+     */
+    public String generateStackEntryName() {
+        return generateStackEntryName(getUiStyle(), getClass());
+    }
+
+    /**
+     * Generates BackStackEntry name for GuidedStepSupportFragment class or empty String if no entry is
+     * associated.  Note {@link #UI_STYLE_ACTIVITY_ROOT} is not allowed and returns empty String.
+     * @param uiStyle {@link #UI_STYLE_REPLACE} or {@link #UI_STYLE_ENTRANCE}
+     * @return BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
+     * associated.
+     */
+    public static String generateStackEntryName(int uiStyle, Class guidedStepFragmentClass) {
+        if (!GuidedStepSupportFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+            return "";
+        }
+        switch (uiStyle) {
+        case UI_STYLE_REPLACE:
+            return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
+        case UI_STYLE_ENTRANCE:
+            return ENTRY_NAME_ENTRANCE + guidedStepFragmentClass.getName();
+        case UI_STYLE_ACTIVITY_ROOT:
+        default:
+            return "";
+        }
+    }
+
+    /**
+     * Returns true if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_ENTRANCE};
+     * false otherwise.
+     * @param backStackEntryName Name of BackStackEntry.
+     * @return True if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_ENTRANCE};
+     * false otherwise.
+     */
+    public static boolean isUiStyleEntrance(String backStackEntryName) {
+        return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE);
+    }
+
+    /**
+     * Returns true if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_REPLACE};
+     * false otherwise.
+     * @param backStackEntryName Name of BackStackEntry.
+     * @return True if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_REPLACE};
+     * false otherwise.
+     */
+    public static boolean isUiStyleDefault(String backStackEntryName) {
+        return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_REPLACE);
+    }
+
+    /**
+     * Extract Class name from BackStackEntry name.
+     * @param backStackEntryName Name of BackStackEntry.
+     * @return Class name of GuidedStepSupportFragment.
+     */
+    public static String getGuidedStepSupportFragmentClassName(String backStackEntryName) {
+        if (backStackEntryName.startsWith(ENTRY_NAME_REPLACE)) {
+            return backStackEntryName.substring(ENTRY_NAME_REPLACE.length());
+        } else if (backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE)) {
+            return backStackEntryName.substring(ENTRY_NAME_ENTRANCE.length());
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Adds the specified GuidedStepSupportFragment as content of Activity; no backstack entry is added so
+     * the activity will be dismissed when BACK key is pressed.
+     * {@link #UI_STYLE_ACTIVITY_ROOT} is assigned.
+     *
+     * Note: currently fragments added using this method must be created programmatically rather
+     * than via XML.
+     * @param activity The Activity to be used to insert GuidedstepFragment.
+     * @param fragment The GuidedStepSupportFragment to be inserted into the fragment stack.
+     * @param id The id of container to add GuidedStepSupportFragment, can be android.R.id.content.
+     * @return The ID returned by the call FragmentTransaction.replace.
+     */
+    public static int addAsRoot(FragmentActivity activity, GuidedStepSupportFragment fragment, int id) {
+        // Workaround b/23764120: call getDecorView() to force requestFeature of ActivityTransition.
+        activity.getWindow().getDecorView();
+
+        FragmentManager fragmentManager = activity.getSupportFragmentManager();
+        FragmentTransaction ft = fragmentManager.beginTransaction();
+        fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
+        return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+    }
+
+    /**
+     * Returns the current GuidedStepSupportFragment on the fragment transaction stack.
+     * @return The current GuidedStepSupportFragment, if any, on the fragment transaction stack.
+     */
+    public static GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(FragmentManager fm) {
+        Fragment f = fm.findFragmentByTag(TAG_LEAN_BACK_ACTIONS_FRAGMENT);
+        if (f instanceof GuidedStepSupportFragment) {
+            return (GuidedStepSupportFragment) f;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the GuidanceStylist that displays guidance information for the user.
+     * @return The GuidanceStylist for this fragment.
+     */
+    public GuidanceStylist getGuidanceStylist() {
+        return mGuidanceStylist;
+    }
+
+    /**
+     * Returns the GuidedActionsStylist that displays the actions the user may take.
+     * @return The GuidedActionsStylist for this fragment.
+     */
+    public GuidedActionsStylist getGuidedActionsStylist() {
+        return mActionsStylist;
+    }
+
+    /**
+     * Returns the list of button GuidedActions that the user may take in this fragment.
+     * @return The list of button GuidedActions for this fragment.
+     */
+    public List<GuidedAction> getButtonActions() {
+        return mButtonActions;
+    }
+
+    /**
+     * Find button GuidedAction by Id.
+     * @param id  Id of the button action to search.
+     * @return  GuidedAction object or null if not found.
+     */
+    public GuidedAction findButtonActionById(long id) {
+        int index = findButtonActionPositionById(id);
+        return index >= 0 ? mButtonActions.get(index) : null;
+    }
+
+    /**
+     * Find button GuidedAction position in array by Id.
+     * @param id  Id of the button action to search.
+     * @return  position of GuidedAction object in array or -1 if not found.
+     */
+    public int findButtonActionPositionById(long id) {
+        if (mButtonActions != null) {
+            for (int i = 0; i < mButtonActions.size(); i++) {
+                GuidedAction action = mButtonActions.get(i);
+                if (mButtonActions.get(i).getId() == id) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the GuidedActionsStylist that displays the button actions the user may take.
+     * @return The GuidedActionsStylist for this fragment.
+     */
+    public GuidedActionsStylist getGuidedButtonActionsStylist() {
+        return mButtonActionsStylist;
+    }
+
+    /**
+     * Sets the list of button GuidedActions that the user may take in this fragment.
+     * @param actions The list of button GuidedActions for this fragment.
+     */
+    public void setButtonActions(List<GuidedAction> actions) {
+        mButtonActions = actions;
+        if (mButtonAdapter != null) {
+            mButtonAdapter.setActions(mButtonActions);
+        }
+    }
+
+    /**
+     * Notify an button action has changed and update its UI.
+     * @param position Position of the button GuidedAction in array.
+     */
+    public void notifyButtonActionChanged(int position) {
+        if (mButtonAdapter != null) {
+            mButtonAdapter.notifyItemChanged(position);
+        }
+    }
+
+    /**
+     * Returns the view corresponding to the button action at the indicated position in the list of
+     * actions for this fragment.
+     * @param position The integer position of the button action of interest.
+     * @return The View corresponding to the button action at the indicated position, or null if
+     * that action is not currently onscreen.
+     */
+    public View getButtonActionItemView(int position) {
+        final RecyclerView.ViewHolder holder = mButtonActionsStylist.getActionsGridView()
+                    .findViewHolderForPosition(position);
+        return holder == null ? null : holder.itemView;
+    }
+
+    /**
+     * Scrolls the action list to the position indicated, selecting that button action's view.
+     * @param position The integer position of the button action of interest.
+     */
+    public void setSelectedButtonActionPosition(int position) {
+        mButtonActionsStylist.getActionsGridView().setSelectedPosition(position);
+    }
+
+    /**
+     * Returns the position if the currently selected button GuidedAction.
+     * @return position The integer position of the currently selected button action.
+     */
+    public int getSelectedButtonActionPosition() {
+        return mButtonActionsStylist.getActionsGridView().getSelectedPosition();
+    }
+
+    /**
+     * Returns the list of GuidedActions that the user may take in this fragment.
+     * @return The list of GuidedActions for this fragment.
+     */
+    public List<GuidedAction> getActions() {
+        return mActions;
+    }
+
+    /**
+     * Find GuidedAction by Id.
+     * @param id  Id of the action to search.
+     * @return  GuidedAction object or null if not found.
+     */
+    public GuidedAction findActionById(long id) {
+        int index = findActionPositionById(id);
+        return index >= 0 ? mActions.get(index) : null;
+    }
+
+    /**
+     * Find GuidedAction position in array by Id.
+     * @param id  Id of the action to search.
+     * @return  position of GuidedAction object in array or -1 if not found.
+     */
+    public int findActionPositionById(long id) {
+        if (mActions != null) {
+            for (int i = 0; i < mActions.size(); i++) {
+                GuidedAction action = mActions.get(i);
+                if (mActions.get(i).getId() == id) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Sets the list of GuidedActions that the user may take in this fragment.
+     * @param actions The list of GuidedActions for this fragment.
+     */
+    public void setActions(List<GuidedAction> actions) {
+        mActions = actions;
+        if (mAdapter != null) {
+            mAdapter.setActions(mActions);
+        }
+    }
+
+    /**
+     * Notify an action has changed and update its UI.
+     * @param position Position of the GuidedAction in array.
+     */
+    public void notifyActionChanged(int position) {
+        if (mAdapter != null) {
+            mAdapter.notifyItemChanged(position);
+        }
+    }
+
+    /**
+     * Returns the view corresponding to the action at the indicated position in the list of
+     * actions for this fragment.
+     * @param position The integer position of the action of interest.
+     * @return The View corresponding to the action at the indicated position, or null if that
+     * action is not currently onscreen.
+     */
+    public View getActionItemView(int position) {
+        final RecyclerView.ViewHolder holder = mActionsStylist.getActionsGridView()
+                    .findViewHolderForPosition(position);
+        return holder == null ? null : holder.itemView;
+    }
+
+    /**
+     * Scrolls the action list to the position indicated, selecting that action's view.
+     * @param position The integer position of the action of interest.
+     */
+    public void setSelectedActionPosition(int position) {
+        mActionsStylist.getActionsGridView().setSelectedPosition(position);
+    }
+
+    /**
+     * Returns the position if the currently selected GuidedAction.
+     * @return position The integer position of the currently selected action.
+     */
+    public int getSelectedActionPosition() {
+        return mActionsStylist.getActionsGridView().getSelectedPosition();
+    }
+
+    /**
+     * Called by Constructor to provide fragment transitions.  The default implementation assigns
+     * transitions based on {@link #getUiStyle()}:
+     * <ul>
+     * <li> {@link #UI_STYLE_REPLACE} Slide from/to end(right) for enter transition, slide from/to
+     * start(left) for exit transition, shared element enter transition is set to ChangeBounds.
+     * <li> {@link #UI_STYLE_ENTRANCE} Enter transition is set to slide from both sides, exit
+     * transition is same as {@link #UI_STYLE_REPLACE}, no shared element enter transition.
+     * <li> {@link #UI_STYLE_ACTIVITY_ROOT} Enter transition is set to null and app should rely on
+     * activity transition, exit transition is same as {@link #UI_STYLE_REPLACE}, no shared element
+     * enter transition.
+     * </ul>
+     * <p>
+     * The default implementation heavily relies on {@link GuidedActionsStylist} and
+     * {@link GuidanceStylist} layout, app may override this method when modifying the default
+     * layout of {@link GuidedActionsStylist} or {@link GuidanceStylist}.
+     * <p>
+     * TIP: because the fragment view is removed during fragment transition, in general app cannot
+     * use two Visibility transition together. Workaround is to create your own Visibility
+     * transition that controls multiple animators (e.g. slide and fade animation in one Transition
+     * class).
+     */
+    protected void onProvideFragmentTransitions() {
+        if (Build.VERSION.SDK_INT >= 21) {
+            final int uiStyle = getUiStyle();
+            if (uiStyle == UI_STYLE_REPLACE) {
+                Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END);
+                TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
+                TransitionHelper.setEnterTransition(this, enterTransition);
+
+                Object changeBounds = TransitionHelper.createChangeBounds(false);
+                TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
+            } else if (uiStyle == UI_STYLE_ENTRANCE) {
+                Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
+                        TransitionHelper.FADE_OUT);
+                TransitionHelper.include(fade, R.id.guidedstep_background);
+                Object slide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
+                        Gravity.START);
+                TransitionHelper.include(slide, R.id.content_fragment);
+                TransitionHelper.include(slide, R.id.action_fragment_root);
+                Object enterTransition = TransitionHelper.createTransitionSet(false);
+                TransitionHelper.addTransition(enterTransition, fade);
+                TransitionHelper.addTransition(enterTransition, slide);
+                TransitionHelper.setEnterTransition(this, enterTransition);
+
+                // No shared element transition
+                TransitionHelper.setSharedElementEnterTransition(this, null);
+            } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
+                // for Activity root, we dont need enter transition, use activity transition
+                TransitionHelper.setEnterTransition(this, null);
+                // No shared element transition
+                TransitionHelper.setSharedElementEnterTransition(this, null);
+            }
+            // exitTransition is same for all style
+            Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
+            TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
+            TransitionHelper.setExitTransition(this, exitTransition);
+        }
+    }
+
+    /**
+     * Called by onCreateView to inflate background view.  Default implementation loads view
+     * from {@link R.layout#lb_guidedstep_background} which holds a reference to
+     * guidedStepBackground.
+     * @param inflater LayoutInflater to load background view.
+     * @param container Parent view of background view.
+     * @param savedInstanceState
+     * @return Created background view or null if no background.
+     */
+    public View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
+    }
+
+    /**
+     * Set UI style to fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when fragment
+     * is first initialized. UI style is used to choose different fragment transition animations and
+     * determine if this is the first GuidedStepSupportFragment on backstack. In most cases app does not
+     * directly call this method, app calls helper function
+     * {@link #add(FragmentManager, GuidedStepSupportFragment, int)}. However if the app creates Fragment
+     * transaction and controls backstack by itself, it would need call setUiStyle() to select the
+     * fragment transition to use.
+     *
+     * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+     *        {@link #UI_STYLE_ENTRANCE}.
+     */
+    public void setUiStyle(int style) {
+        int oldStyle = getUiStyle();
+        Bundle arguments = getArguments();
+        boolean isNew = false;
+        if (arguments == null) {
+            arguments = new Bundle();
+            isNew = true;
+        }
+        arguments.putInt(EXTRA_UI_STYLE, style);
+        // call setArgument() will validate if the fragment is already added.
+        if (isNew) {
+            setArguments(arguments);
+        }
+        if (style != oldStyle) {
+            onProvideFragmentTransitions();
+        }
+    }
+
+    /**
+     * Read UI style from fragment arguments.  Default value is {@link #UI_STYLE_ENTRANCE} when
+     * fragment is first initialized.  UI style is used to choose different fragment transition
+     * animations and determine if this is the first GuidedStepSupportFragment on backstack.
+     *
+     * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+     * {@link #UI_STYLE_ENTRANCE}.
+     * @see #onProvideFragmentTransitions()
+     */
+    public int getUiStyle() {
+        Bundle b = getArguments();
+        if (b == null) return UI_STYLE_ENTRANCE;
+        return b.getInt(EXTRA_UI_STYLE, UI_STYLE_ENTRANCE);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (DEBUG) Log.v(TAG, "onCreate");
+        // Set correct transition from saved arguments.
+        onProvideFragmentTransitions();
+        Bundle state = (savedInstanceState != null) ? savedInstanceState : getArguments();
+        if (state != null) {
+            if (mSelectedIndex == -1) {
+                mSelectedIndex = state.getInt(EXTRA_ACTION_SELECTED_INDEX, -1);
+            }
+        }
+        ArrayList<GuidedAction> actions = new ArrayList<GuidedAction>();
+        onCreateActions(actions, savedInstanceState);
+        setActions(actions);
+        ArrayList<GuidedAction> buttonActions = new ArrayList<GuidedAction>();
+        onCreateButtonActions(buttonActions, savedInstanceState);
+        setButtonActions(buttonActions);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDestroyView() {
+        mGuidanceStylist.onDestroyView();
+        mActionsStylist.onDestroyView();
+        mButtonActionsStylist.onDestroyView();
+        mAdapter = null;
+        mButtonAdapter = null;
+        mAdapterGroup = null;
+        super.onDestroyView();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        if (DEBUG) Log.v(TAG, "onCreateView");
+
+        resolveTheme();
+        inflater = getThemeInflater(inflater);
+
+        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_guidedstep_fragment,
+                container, false);
+        ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
+        ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
+
+        Guidance guidance = onCreateGuidance(savedInstanceState);
+        View guidanceView = mGuidanceStylist.onCreateView(inflater, guidanceContainer, guidance);
+        guidanceContainer.addView(guidanceView);
+
+        View actionsView = mActionsStylist.onCreateView(inflater, actionContainer);
+        actionContainer.addView(actionsView);
+
+        View buttonActionsView = mButtonActionsStylist.onCreateView(inflater, actionContainer);
+        mButtonActionsStylist.setAsButtonActions();
+        actionContainer.addView(buttonActionsView);
+
+        GuidedActionAdapter.EditListener editListener = new GuidedActionAdapter.EditListener() {
+
+                @Override
+                public void onImeOpen() {
+                    runImeAnimations(true);
+                }
+
+                @Override
+                public void onImeClose() {
+                    runImeAnimations(false);
+                }
+
+                @Override
+                public long onGuidedActionEdited(GuidedAction action) {
+                    return GuidedStepSupportFragment.this.onGuidedActionEditedAndProceed(action);
+                }
+        };
+
+        mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+        mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, mButtonActionsStylist);
+        mAdapterGroup = new GuidedActionAdapterGroup();
+        mAdapterGroup.addAdpter(mAdapter);
+        mAdapterGroup.addAdpter(mButtonAdapter);
+        mAdapterGroup.setEditListener(editListener);
+
+        mActionsStylist.getActionsGridView().setAdapter(mAdapter);
+        mButtonActionsStylist.getActionsGridView().setAdapter(mButtonAdapter);
+        if (mButtonActions.size() == 0) {
+            // when there is no button actions, we dont need show the second panel, but keep
+            // the width zero to run ChangeBounds transition.
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+                    buttonActionsView.getLayoutParams();
+            lp.weight = 0;
+            buttonActionsView.setLayoutParams(lp);
+        } else {
+            // when there are two actions panel, we need adjust the weight of action to
+            // guidedActionContentWidthWeightTwoPanels.
+            Context ctx = mThemeWrapper != null ? mThemeWrapper : getActivity();
+            TypedValue typedValue = new TypedValue();
+            if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
+                    typedValue, true)) {
+                View actionsRoot = root.findViewById(R.id.action_fragment_root);
+                float weight = typedValue.getFloat();
+                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionsRoot
+                        .getLayoutParams();
+                lp.weight = weight;
+                actionsRoot.setLayoutParams(lp);
+            }
+        }
+
+        int pos = (mSelectedIndex >= 0 && mSelectedIndex < mActions.size()) ?
+                mSelectedIndex : getFirstCheckedAction();
+        setSelectedActionPosition(pos);
+
+        setSelectedButtonActionPosition(0);
+
+        View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
+        if (backgroundView != null) {
+            root.addView(backgroundView, 0);
+        }
+        return root;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mActionsStylist.getActionsGridView().requestFocus();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(EXTRA_ACTION_SELECTED_INDEX,
+                (mActionsStylist.getActionsGridView() != null) ?
+                        getSelectedActionPosition() : mSelectedIndex);
+    }
+
+    private static boolean isGuidedStepTheme(Context context) {
+        int resId = R.attr.guidedStepThemeFlag;
+        TypedValue typedValue = new TypedValue();
+        boolean found = context.getTheme().resolveAttribute(resId, typedValue, true);
+        if (DEBUG) Log.v(TAG, "Found guided step theme flag? " + found);
+        return found && typedValue.type == TypedValue.TYPE_INT_BOOLEAN && typedValue.data != 0;
+    }
+
+    /**
+     * Convenient method to close GuidedStepSupportFragments on top of other content or finish Activity if
+     * GuidedStepSupportFragments were started in a separate activity.  Pops all stack entries including
+     * {@link #UI_STYLE_ENTRANCE}; if {@link #UI_STYLE_ENTRANCE} is not found, finish the activity.
+     * Note that this method must be paired with {@link #add(FragmentManager, GuidedStepSupportFragment,
+     * int)} which sets up the stack entry name for finding which fragment we need to pop back to.
+     */
+    public void finishGuidedStepSupportFragments() {
+        final FragmentManager fragmentManager = getFragmentManager();
+        final int entryCount = fragmentManager.getBackStackEntryCount();
+        if (entryCount > 0) {
+            for (int i = entryCount - 1; i >= 0; i--) {
+                BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+                if (isUiStyleEntrance(entry.getName())) {
+                    GuidedStepSupportFragment top = getCurrentGuidedStepSupportFragment(fragmentManager);
+                    if (top != null) {
+                        top.setUiStyle(UI_STYLE_ENTRANCE);
+                    }
+                    fragmentManager.popBackStack(entry.getId(),
+                            FragmentManager.POP_BACK_STACK_INCLUSIVE);
+                    return;
+                }
+            }
+        }
+        ActivityCompat.finishAfterTransition(getActivity());
+    }
+
+    /**
+     * Convenient method to pop to fragment with Given class.
+     * @param  guidedStepFragmentClass  Name of the Class of GuidedStepSupportFragment to pop to.
+     * @param flags Either 0 or {@link FragmentManager#POP_BACK_STACK_INCLUSIVE}.
+     */
+    public void popBackStackToGuidedStepSupportFragment(Class guidedStepFragmentClass, int flags) {
+        if (!GuidedStepSupportFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+            return;
+        }
+        final FragmentManager fragmentManager = getFragmentManager();
+        final int entryCount = fragmentManager.getBackStackEntryCount();
+        String className = guidedStepFragmentClass.getName();
+        if (entryCount > 0) {
+            for (int i = entryCount - 1; i >= 0; i--) {
+                BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+                String entryClassName = getGuidedStepSupportFragmentClassName(entry.getName());
+                if (className.equals(entryClassName)) {
+                    fragmentManager.popBackStack(entry.getId(), flags);
+                    return;
+                }
+            }
+        }
+    }
+
+    private void resolveTheme() {
+        // Look up the guidedStepTheme in the currently specified theme.  If it exists,
+        // replace the theme with its value.
+        FragmentActivity activity = getActivity();
+        if (mTheme == -1 && !isGuidedStepTheme(activity)) {
+            // Look up the guidedStepTheme in the activity's currently specified theme.  If it
+            // exists, replace the theme with its value.
+            int resId = R.attr.guidedStepTheme;
+            TypedValue typedValue = new TypedValue();
+            boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
+            if (DEBUG) Log.v(TAG, "Found guided step theme reference? " + found);
+            if (found) {
+                ContextThemeWrapper themeWrapper =
+                        new ContextThemeWrapper(activity, typedValue.resourceId);
+                if (isGuidedStepTheme(themeWrapper)) {
+                    mTheme = typedValue.resourceId;
+                    mThemeWrapper = themeWrapper;
+                } else {
+                    found = false;
+                    mThemeWrapper = null;
+                }
+            }
+            if (!found) {
+                Log.e(TAG, "GuidedStepSupportFragment does not have an appropriate theme set.");
+            }
+        } else if (mTheme != -1) {
+            mThemeWrapper = new ContextThemeWrapper(activity, mTheme);
+        }
+    }
+
+    private LayoutInflater getThemeInflater(LayoutInflater inflater) {
+        if (mTheme == -1) {
+            return inflater;
+        } else {
+            return inflater.cloneInContext(mThemeWrapper);
+        }
+    }
+
+    private int getFirstCheckedAction() {
+        for (int i = 0, size = mActions.size(); i < size; i++) {
+            if (mActions.get(i).isChecked()) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    private void runImeAnimations(boolean entering) {
+        ArrayList<Animator> animators = new ArrayList<Animator>();
+        if (entering) {
+            mGuidanceStylist.onImeAppearing(animators);
+            mActionsStylist.onImeAppearing(animators);
+            mButtonActionsStylist.onImeAppearing(animators);
+        } else {
+            mGuidanceStylist.onImeDisappearing(animators);
+            mActionsStylist.onImeDisappearing(animators);
+            mButtonActionsStylist.onImeDisappearing(animators);
+        }
+        AnimatorSet set = new AnimatorSet();
+        set.playTogether(animators);
+        set.start();
+    }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
index b2c9b1c..219bb98 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
@@ -138,8 +138,10 @@
         if (getBridgeAdapter() != null) {
             FocusHighlightHelper.setupHeaderItemFocusHighlight(listView);
         }
-        view.setBackgroundColor(getBackgroundColor());
-        updateFadingEdgeToBrandColor(getBackgroundColor());
+        if (mBackgroundColorSet) {
+            view.setBackgroundColor(mBackgroundColor);
+            updateFadingEdgeToBrandColor(mBackgroundColor);
+        }
         updateListViewVisibility();
     }
 
@@ -228,22 +230,6 @@
         }
     }
 
-    int getBackgroundColor() {
-        if (getActivity() == null) {
-            throw new IllegalStateException("Activity must be attached");
-        }
-
-        if (mBackgroundColorSet) {
-            return mBackgroundColor;
-        }
-
-        TypedValue outValue = new TypedValue();
-        if (getActivity().getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
-            return getResources().getColor(outValue.resourceId);
-        }
-        return getResources().getColor(R.color.lb_default_brand_color);
-    }
-
     @Override
     void onTransitionStart() {
         super.onTransitionStart();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java
index 9c66714..ecf04d8 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java
@@ -140,8 +140,10 @@
         if (getBridgeAdapter() != null) {
             FocusHighlightHelper.setupHeaderItemFocusHighlight(listView);
         }
-        view.setBackgroundColor(getBackgroundColor());
-        updateFadingEdgeToBrandColor(getBackgroundColor());
+        if (mBackgroundColorSet) {
+            view.setBackgroundColor(mBackgroundColor);
+            updateFadingEdgeToBrandColor(mBackgroundColor);
+        }
         updateListViewVisibility();
     }
 
@@ -230,22 +232,6 @@
         }
     }
 
-    int getBackgroundColor() {
-        if (getActivity() == null) {
-            throw new IllegalStateException("Activity must be attached");
-        }
-
-        if (mBackgroundColorSet) {
-            return mBackgroundColor;
-        }
-
-        TypedValue outValue = new TypedValue();
-        if (getActivity().getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
-            return getResources().getColor(outValue.resourceId);
-        }
-        return getResources().getColor(R.color.lb_default_brand_color);
-    }
-
     @Override
     void onTransitionStart() {
         super.onTransitionStart();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
index 8c56925..e3af403 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
@@ -74,7 +74,7 @@
  */
 public abstract class PlaybackControlGlue implements OnActionClickedListener, View.OnKeyListener {
     /**
-     * The adapter key for the first custom control on the right side
+     * The adapter key for the first custom control on the left side
      * of the predefined primary controls.
      */
     public static final int ACTION_CUSTOM_LEFT_FIRST = 0x1;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
new file mode 100644
index 0000000..5857e65
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
@@ -0,0 +1,858 @@
+/* This file is auto-generated from PlaybackControlGlue.java.  DO NOT MODIFY. */
+
+package android.support.v17.leanback.app;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.View;
+
+
+/**
+ * A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow} and
+ * {@link PlaybackOverlaySupportFragment} that implements a recommended approach to handling standard
+ * playback control actions such as play/pause, fast forward/rewind at progressive speed levels,
+ * and skip to next/previous.  This helper class is a glue layer in that it manages the
+ * configuration of and interaction between the leanback UI components by defining a functional
+ * interface to the media player.
+ *
+ * <p>You can instantiate a concrete subclass such as {@link MediaControllerGlue} or you must
+ * subclass this abstract helper.  To create a subclass you must implement all of the
+ * abstract methods and the subclass must invoke {@link #onMetadataChanged()} and
+ * {@link #onStateChanged()} appropriately.
+ * </p>
+ *
+ * <p>To use an instance of the glue layer, first construct an instance.  Constructor parameters
+ * inform the glue what speed levels are supported for fast forward/rewind.  Providing a
+ * {@link android.support.v17.leanback.app.PlaybackOverlaySupportFragment} is optional.
+ * </p>
+ *
+ * <p>If you have your own controls row you must pass it to {@link #setControlsRow}.
+ * The row will be updated by the glue layer based on the media metadata and playback state.
+ * Alternatively, you may call {@link #createControlsRowAndPresenter()} which will set a controls
+ * row and return a row presenter you can use to present the row.
+ * </p>
+ *
+ * <p>The helper sets a {@link android.support.v17.leanback.widget.SparseArrayObjectAdapter}
+ * on the controls row as the primary actions adapter, and adds actions to it.  You can provide
+ * additional actions by overriding {@link #createPrimaryActionsAdapter}.  This helper does not
+ * deal in secondary actions so those you may add separately.
+ * </p>
+ *
+ * <p>Provide a click listener on your fragment and if an action is clicked, call
+ * {@link #onActionClicked}.  There is no need to call {@link #setOnItemViewClickedListener}
+ * but if you do a click listener will be installed on the fragment and recognized action clicks
+ * will be handled.  Your listener will be called only for unhandled actions.
+ * </p>
+ *
+ * <p>The helper implements a key event handler.  If you pass a
+ * {@link android.support.v17.leanback.app.PlaybackOverlaySupportFragment} the fragment's input event
+ * handler will be set.  Otherwise, you should set the glue object as key event handler to the
+ * ViewHolder when bound by your row presenter; see
+ * {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}.
+ * </p>
+ *
+ * <p>To update the controls row progress during playback, override {@link #enableProgressUpdating}
+ * to manage the lifecycle of a periodic callback to {@link #updateProgress()}.
+ * {@link #getUpdatePeriod()} provides a recommended update period.
+ * </p>
+ *
+ */
+public abstract class PlaybackControlSupportGlue implements OnActionClickedListener, View.OnKeyListener {
+    /**
+     * The adapter key for the first custom control on the left side
+     * of the predefined primary controls.
+     */
+    public static final int ACTION_CUSTOM_LEFT_FIRST = 0x1;
+
+    /**
+     * The adapter key for the skip to previous control.
+     */
+    public static final int ACTION_SKIP_TO_PREVIOUS = 0x10;
+
+    /**
+     * The adapter key for the rewind control.
+     */
+    public static final int ACTION_REWIND = 0x20;
+
+    /**
+     * The adapter key for the play/pause control.
+     */
+    public static final int ACTION_PLAY_PAUSE = 0x40;
+
+    /**
+     * The adapter key for the fast forward control.
+     */
+    public static final int ACTION_FAST_FORWARD = 0x80;
+
+    /**
+     * The adapter key for the skip to next control.
+     */
+    public static final int ACTION_SKIP_TO_NEXT = 0x100;
+
+    /**
+     * The adapter key for the first custom control on the right side
+     * of the predefined primary controls.
+     */
+    public static final int ACTION_CUSTOM_RIGHT_FIRST = 0x1000;
+
+    /**
+     * Invalid playback speed.
+     */
+    public static final int PLAYBACK_SPEED_INVALID = -1;
+
+    /**
+     * Speed representing playback state that is paused.
+     */
+    public static final int PLAYBACK_SPEED_PAUSED = 0;
+
+    /**
+     * Speed representing playback state that is playing normally.
+     */
+    public static final int PLAYBACK_SPEED_NORMAL = 1;
+
+    /**
+     * The initial (level 0) fast forward playback speed.
+     * The negative of this value is for rewind at the same speed.
+     */
+    public static final int PLAYBACK_SPEED_FAST_L0 = 10;
+
+    /**
+     * The level 1 fast forward playback speed.
+     * The negative of this value is for rewind at the same speed.
+     */
+    public static final int PLAYBACK_SPEED_FAST_L1 = 11;
+
+    /**
+     * The level 2 fast forward playback speed.
+     * The negative of this value is for rewind at the same speed.
+     */
+    public static final int PLAYBACK_SPEED_FAST_L2 = 12;
+
+    /**
+     * The level 3 fast forward playback speed.
+     * The negative of this value is for rewind at the same speed.
+     */
+    public static final int PLAYBACK_SPEED_FAST_L3 = 13;
+
+    /**
+     * The level 4 fast forward playback speed.
+     * The negative of this value is for rewind at the same speed.
+     */
+    public static final int PLAYBACK_SPEED_FAST_L4 = 14;
+
+    private static final String TAG = "PlaybackControlSupportGlue";
+    private static final boolean DEBUG = false;
+
+    private static final int MSG_UPDATE_PLAYBACK_STATE = 100;
+    private static final int UPDATE_PLAYBACK_STATE_DELAY_MS = 2000;
+    private static final int NUMBER_OF_SEEK_SPEEDS = PLAYBACK_SPEED_FAST_L4 -
+            PLAYBACK_SPEED_FAST_L0 + 1;
+
+    private final PlaybackOverlaySupportFragment mFragment;
+    private final Context mContext;
+    private final int[] mFastForwardSpeeds;
+    private final int[] mRewindSpeeds;
+    private PlaybackControlsRow mControlsRow;
+    private SparseArrayObjectAdapter mPrimaryActionsAdapter;
+    private PlaybackControlsRow.PlayPauseAction mPlayPauseAction;
+    private PlaybackControlsRow.SkipNextAction mSkipNextAction;
+    private PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction;
+    private PlaybackControlsRow.FastForwardAction mFastForwardAction;
+    private PlaybackControlsRow.RewindAction mRewindAction;
+    private OnItemViewClickedListener mExternalOnItemViewClickedListener;
+    private int mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
+    private boolean mFadeWhenPlaying = true;
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == MSG_UPDATE_PLAYBACK_STATE) {
+                updatePlaybackState();
+            }
+        }
+    };
+
+    private final OnItemViewClickedListener mOnItemViewClickedListener =
+            new OnItemViewClickedListener() {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder viewHolder, Object object,
+                                  RowPresenter.ViewHolder viewHolder2, Row row) {
+            if (DEBUG) Log.v(TAG, "onItemClicked " + object);
+            boolean handled = false;
+            if (object instanceof Action) {
+                handled = dispatchAction((Action) object, null);
+            }
+            if (!handled && mExternalOnItemViewClickedListener != null) {
+                mExternalOnItemViewClickedListener.onItemClicked(viewHolder, object,
+                        viewHolder2, row);
+            }
+        }
+    };
+
+    /**
+     * Constructor for the glue.
+     *
+     * @param context
+     * @param seekSpeeds Array of seek speeds for fast forward and rewind.
+     */
+    public PlaybackControlSupportGlue(Context context, int[] seekSpeeds) {
+        this(context, null, seekSpeeds, seekSpeeds);
+    }
+
+    /**
+     * Constructor for the glue.
+     *
+     * @param context
+     * @param fastForwardSpeeds Array of seek speeds for fast forward.
+     * @param rewindSpeeds Array of seek speeds for rewind.
+     */
+    public PlaybackControlSupportGlue(Context context,
+                               int[] fastForwardSpeeds,
+                               int[] rewindSpeeds) {
+        this(context, null, fastForwardSpeeds, rewindSpeeds);
+    }
+
+    /**
+     * Constructor for the glue.
+     *
+     * @param context
+     * @param fragment Optional; if using a {@link PlaybackOverlaySupportFragment}, pass it in.
+     * @param seekSpeeds Array of seek speeds for fast forward and rewind.
+     */
+    public PlaybackControlSupportGlue(Context context,
+                               PlaybackOverlaySupportFragment fragment,
+                               int[] seekSpeeds) {
+        this(context, fragment, seekSpeeds, seekSpeeds);
+    }
+
+    /**
+     * Constructor for the glue.
+     *
+     * @param context
+     * @param fragment Optional; if using a {@link PlaybackOverlaySupportFragment}, pass it in.
+     * @param fastForwardSpeeds Array of seek speeds for fast forward.
+     * @param rewindSpeeds Array of seek speeds for rewind.
+     */
+    public PlaybackControlSupportGlue(Context context,
+                               PlaybackOverlaySupportFragment fragment,
+                               int[] fastForwardSpeeds,
+                               int[] rewindSpeeds) {
+        mContext = context;
+        mFragment = fragment;
+        if (fragment != null) {
+            attachToFragment();
+        }
+        if (fastForwardSpeeds.length == 0 || fastForwardSpeeds.length > NUMBER_OF_SEEK_SPEEDS) {
+            throw new IllegalStateException("invalid fastForwardSpeeds array size");
+        }
+        mFastForwardSpeeds = fastForwardSpeeds;
+        if (rewindSpeeds.length == 0 || rewindSpeeds.length > NUMBER_OF_SEEK_SPEEDS) {
+            throw new IllegalStateException("invalid rewindSpeeds array size");
+        }
+        mRewindSpeeds = rewindSpeeds;
+    }
+
+    private final PlaybackOverlaySupportFragment.InputEventHandler mOnInputEventHandler =
+            new PlaybackOverlaySupportFragment.InputEventHandler() {
+        @Override
+        public boolean handleInputEvent(InputEvent event) {
+            if (event instanceof KeyEvent) {
+                KeyEvent keyEvent = (KeyEvent) event;
+                return onKey(null, keyEvent.getKeyCode(), keyEvent);
+            }
+            return false;
+        }
+    };
+
+    private void attachToFragment() {
+        mFragment.setInputEventHandler(mOnInputEventHandler);
+    }
+
+    /**
+     * Helper method for instantiating a
+     * {@link android.support.v17.leanback.widget.PlaybackControlsRow} and corresponding
+     * {@link android.support.v17.leanback.widget.PlaybackControlsRowPresenter}.
+     */
+    public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
+        PlaybackControlsRow controlsRow = new PlaybackControlsRow(this);
+        setControlsRow(controlsRow);
+
+        AbstractDetailsDescriptionPresenter detailsPresenter =
+                new AbstractDetailsDescriptionPresenter() {
+            @Override
+            protected void onBindDescription(AbstractDetailsDescriptionPresenter.ViewHolder
+                                                     viewHolder, Object object) {
+                PlaybackControlSupportGlue glue = (PlaybackControlSupportGlue) object;
+                if (glue.hasValidMedia()) {
+                    viewHolder.getTitle().setText(glue.getMediaTitle());
+                    viewHolder.getSubtitle().setText(glue.getMediaSubtitle());
+                } else {
+                    viewHolder.getTitle().setText("");
+                    viewHolder.getSubtitle().setText("");
+                }
+            }
+        };
+        return new PlaybackControlsRowPresenter(detailsPresenter) {
+            @Override
+            protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
+                super.onBindRowViewHolder(vh, item);
+                vh.setOnKeyListener(PlaybackControlSupportGlue.this);
+            }
+            @Override
+            protected void onUnbindRowViewHolder(RowPresenter.ViewHolder vh) {
+                super.onUnbindRowViewHolder(vh);
+                vh.setOnKeyListener(null);
+            }
+        };
+    }
+
+    /**
+     * Returns the fragment.
+     */
+    public PlaybackOverlaySupportFragment getFragment() {
+        return mFragment;
+    }
+
+    /**
+     * Returns the context.
+     */
+    public Context getContext() {
+        return mContext;
+    }
+
+    /**
+     * Returns the fast forward speeds.
+     */
+    public int[] getFastForwardSpeeds() {
+        return mFastForwardSpeeds;
+    }
+
+    /**
+     * Returns the rewind speeds.
+     */
+    public int[] getRewindSpeeds() {
+        return mRewindSpeeds;
+    }
+
+    /**
+     * Sets the controls to fade after a timeout when media is playing.
+     */
+    public void setFadingEnabled(boolean enable) {
+        mFadeWhenPlaying = enable;
+        if (!mFadeWhenPlaying && mFragment != null) {
+            mFragment.setFadingEnabled(false);
+        }
+    }
+
+    /**
+     * Returns true if controls are set to fade when media is playing.
+     */
+    public boolean isFadingEnabled() {
+        return mFadeWhenPlaying;
+    }
+
+    /**
+     * Set the {@link OnItemViewClickedListener} to be called if the click event
+     * is not handled internally.
+     * @param listener
+     * @deprecated Don't call this.  Instead set the listener on the fragment yourself,
+     * and call {@link #onActionClicked} to handle clicks.
+     */
+    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+        mExternalOnItemViewClickedListener = listener;
+        if (mFragment != null) {
+            mFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        }
+    }
+
+    /**
+     * Returns the {@link OnItemViewClickedListener}.
+     */
+    public OnItemViewClickedListener getOnItemViewClickedListener() {
+        return mExternalOnItemViewClickedListener;
+    }
+
+    /**
+     * Sets the controls row to be managed by the glue layer.
+     * The primary actions and playback state related aspects of the row
+     * are updated by the glue.
+     */
+    public void setControlsRow(PlaybackControlsRow controlsRow) {
+        mControlsRow = controlsRow;
+        mPrimaryActionsAdapter = createPrimaryActionsAdapter(
+                new ControlButtonPresenterSelector());
+        mControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter);
+        updateControlsRow();
+    }
+
+    /**
+     * Returns the playback controls row managed by the glue layer.
+     */
+    public PlaybackControlsRow getControlsRow() {
+        return mControlsRow;
+    }
+
+    /**
+     * Override this to start/stop a runnable to call {@link #updateProgress} at
+     * an interval such as {@link #getUpdatePeriod}.
+     */
+    public void enableProgressUpdating(boolean enable) {
+    }
+
+    /**
+     * Returns the time period in milliseconds that should be used
+     * to update the progress.  See {@link #updateProgress()}.
+     */
+    public int getUpdatePeriod() {
+        // TODO: calculate a better update period based on total duration and screen size
+        return 500;
+    }
+
+    /**
+     * Updates the progress bar based on the current media playback position.
+     */
+    public void updateProgress() {
+        int position = getCurrentPosition();
+        if (DEBUG) Log.v(TAG, "updateProgress " + position);
+        mControlsRow.setCurrentTime(position);
+    }
+
+    /**
+     * Handles action clicks.  A subclass may override this add support for additional actions.
+     */
+    @Override
+    public void onActionClicked(Action action) {
+        dispatchAction(action, null);
+    }
+
+    /**
+     * Handles key events and returns true if handled.  A subclass may override this to provide
+     * additional support.
+     */
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_BACK:
+            case KeyEvent.KEYCODE_ESCAPE:
+                boolean abortSeek = mPlaybackSpeed >= PLAYBACK_SPEED_FAST_L0 ||
+                        mPlaybackSpeed <= -PLAYBACK_SPEED_FAST_L0;
+                if (abortSeek) {
+                    mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
+                    startPlayback(mPlaybackSpeed);
+                    updatePlaybackStatusAfterUserAction();
+                    return keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE;
+                }
+                return false;
+        }
+        Action action = mControlsRow.getActionForKeyCode(mPrimaryActionsAdapter, keyCode);
+        if (action != null) {
+            if (action == mPrimaryActionsAdapter.lookup(ACTION_PLAY_PAUSE) ||
+                    action == mPrimaryActionsAdapter.lookup(ACTION_REWIND) ||
+                    action == mPrimaryActionsAdapter.lookup(ACTION_FAST_FORWARD) ||
+                    action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_PREVIOUS) ||
+                    action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_NEXT)) {
+                if (((KeyEvent) event).getAction() == KeyEvent.ACTION_DOWN) {
+                    dispatchAction(action, (KeyEvent) event);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called when the given action is invoked, either by click or keyevent.
+     */
+    private boolean dispatchAction(Action action, KeyEvent keyEvent) {
+        boolean handled = false;
+        if (action == mPlayPauseAction) {
+            boolean canPlay = keyEvent == null ||
+                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
+                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY;
+            boolean canPause = keyEvent == null ||
+                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
+                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE;
+            if (mPlaybackSpeed != PLAYBACK_SPEED_NORMAL) {
+                if (canPlay) {
+                    mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
+                    startPlayback(mPlaybackSpeed);
+                }
+            } else if (canPause) {
+                mPlaybackSpeed = PLAYBACK_SPEED_PAUSED;
+                pausePlayback();
+            }
+            updatePlaybackStatusAfterUserAction();
+            handled = true;
+        } else if (action == mSkipNextAction) {
+            skipToNext();
+            handled = true;
+        } else if (action == mSkipPreviousAction) {
+            skipToPrevious();
+            handled = true;
+        } else if (action == mFastForwardAction) {
+            if (mPlaybackSpeed < getMaxForwardSpeedId()) {
+                switch (mPlaybackSpeed) {
+                    case PLAYBACK_SPEED_FAST_L0:
+                    case PLAYBACK_SPEED_FAST_L1:
+                    case PLAYBACK_SPEED_FAST_L2:
+                    case PLAYBACK_SPEED_FAST_L3:
+                        mPlaybackSpeed++;
+                        break;
+                    default:
+                        mPlaybackSpeed = PLAYBACK_SPEED_FAST_L0;
+                        break;
+                }
+                startPlayback(mPlaybackSpeed);
+                updatePlaybackStatusAfterUserAction();
+            }
+            handled = true;
+        } else if (action == mRewindAction) {
+            if (mPlaybackSpeed > -getMaxRewindSpeedId()) {
+                switch (mPlaybackSpeed) {
+                    case -PLAYBACK_SPEED_FAST_L0:
+                    case -PLAYBACK_SPEED_FAST_L1:
+                    case -PLAYBACK_SPEED_FAST_L2:
+                    case -PLAYBACK_SPEED_FAST_L3:
+                        mPlaybackSpeed--;
+                        break;
+                    default:
+                        mPlaybackSpeed = -PLAYBACK_SPEED_FAST_L0;
+                        break;
+                }
+                startPlayback(mPlaybackSpeed);
+                updatePlaybackStatusAfterUserAction();
+            }
+            handled = true;
+        }
+        return handled;
+    }
+
+    private int getMaxForwardSpeedId() {
+        return PLAYBACK_SPEED_FAST_L0 + (mFastForwardSpeeds.length - 1);
+    }
+
+    private int getMaxRewindSpeedId() {
+        return PLAYBACK_SPEED_FAST_L0 + (mRewindSpeeds.length - 1);
+    }
+
+    private void updateControlsRow() {
+        updateRowMetadata();
+        mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+        updatePlaybackState();
+    }
+
+    private void updatePlaybackStatusAfterUserAction() {
+        updatePlaybackState(mPlaybackSpeed);
+        // Sync playback state after a delay
+        mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
+                UPDATE_PLAYBACK_STATE_DELAY_MS);
+    }
+
+    private void updateRowMetadata() {
+        if (mControlsRow == null) {
+            return;
+        }
+
+        if (DEBUG) Log.v(TAG, "updateRowMetadata hasValidMedia " + hasValidMedia());
+
+        if (!hasValidMedia()) {
+            mControlsRow.setImageDrawable(null);
+            mControlsRow.setTotalTime(0);
+            mControlsRow.setCurrentTime(0);
+        } else {
+            mControlsRow.setImageDrawable(getMediaArt());
+            mControlsRow.setTotalTime(getMediaDuration());
+            mControlsRow.setCurrentTime(getCurrentPosition());
+        }
+
+        onRowChanged(mControlsRow);
+    }
+
+    private void updatePlaybackState() {
+        if (hasValidMedia()) {
+            mPlaybackSpeed = getCurrentSpeedId();
+            updatePlaybackState(mPlaybackSpeed);
+        }
+    }
+
+    private void updatePlaybackState(int playbackSpeed) {
+        if (mControlsRow == null) {
+            return;
+        }
+
+        final long actions = getSupportedActions();
+        if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0) {
+            if (mSkipPreviousAction == null) {
+                mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(mContext);
+            }
+            mPrimaryActionsAdapter.set(ACTION_SKIP_TO_PREVIOUS, mSkipPreviousAction);
+        } else {
+            mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_PREVIOUS);
+            mSkipPreviousAction = null;
+        }
+        if ((actions & ACTION_REWIND) != 0) {
+            if (mRewindAction == null) {
+                mRewindAction = new PlaybackControlsRow.RewindAction(mContext,
+                        mRewindSpeeds.length);
+            }
+            mPrimaryActionsAdapter.set(ACTION_REWIND, mRewindAction);
+        } else {
+            mPrimaryActionsAdapter.clear(ACTION_REWIND);
+            mRewindAction = null;
+        }
+        if ((actions & ACTION_PLAY_PAUSE) != 0) {
+            if (mPlayPauseAction == null) {
+                mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(mContext);
+            }
+            mPrimaryActionsAdapter.set(ACTION_PLAY_PAUSE, mPlayPauseAction);
+        } else {
+            mPrimaryActionsAdapter.clear(ACTION_PLAY_PAUSE);
+            mPlayPauseAction = null;
+        }
+        if ((actions & ACTION_FAST_FORWARD) != 0) {
+            if (mFastForwardAction == null) {
+                mFastForwardAction = new PlaybackControlsRow.FastForwardAction(mContext,
+                        mFastForwardSpeeds.length);
+            }
+            mPrimaryActionsAdapter.set(ACTION_FAST_FORWARD, mFastForwardAction);
+        } else {
+            mPrimaryActionsAdapter.clear(ACTION_FAST_FORWARD);
+            mFastForwardAction = null;
+        }
+        if ((actions & ACTION_SKIP_TO_NEXT) != 0) {
+            if (mSkipNextAction == null) {
+                mSkipNextAction = new PlaybackControlsRow.SkipNextAction(mContext);
+            }
+            mPrimaryActionsAdapter.set(ACTION_SKIP_TO_NEXT, mSkipNextAction);
+        } else {
+            mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_NEXT);
+            mSkipNextAction = null;
+        }
+
+        if (mFastForwardAction != null) {
+            int index = 0;
+            if (playbackSpeed >= PLAYBACK_SPEED_FAST_L0) {
+                index = playbackSpeed - PLAYBACK_SPEED_FAST_L0;
+                if (playbackSpeed < getMaxForwardSpeedId()) {
+                    index++;
+                }
+            }
+            if (mFastForwardAction.getIndex() != index) {
+                mFastForwardAction.setIndex(index);
+                notifyItemChanged(mPrimaryActionsAdapter, mFastForwardAction);
+            }
+        }
+        if (mRewindAction != null) {
+            int index = 0;
+            if (playbackSpeed <= -PLAYBACK_SPEED_FAST_L0) {
+                index = -playbackSpeed - PLAYBACK_SPEED_FAST_L0;
+                if (-playbackSpeed < getMaxRewindSpeedId()) {
+                    index++;
+                }
+            }
+            if (mRewindAction.getIndex() != index) {
+                mRewindAction.setIndex(index);
+                notifyItemChanged(mPrimaryActionsAdapter, mRewindAction);
+            }
+        }
+
+        if (playbackSpeed == PLAYBACK_SPEED_PAUSED) {
+            updateProgress();
+            enableProgressUpdating(false);
+        } else {
+            enableProgressUpdating(true);
+        }
+
+        if (mFadeWhenPlaying && mFragment != null) {
+            mFragment.setFadingEnabled(playbackSpeed == PLAYBACK_SPEED_NORMAL);
+        }
+
+        if (mPlayPauseAction != null) {
+            int index = playbackSpeed == PLAYBACK_SPEED_PAUSED ?
+                    PlaybackControlsRow.PlayPauseAction.PLAY :
+                    PlaybackControlsRow.PlayPauseAction.PAUSE;
+            if (mPlayPauseAction.getIndex() != index) {
+                mPlayPauseAction.setIndex(index);
+                notifyItemChanged(mPrimaryActionsAdapter, mPlayPauseAction);
+            }
+        }
+    }
+
+    private static void notifyItemChanged(SparseArrayObjectAdapter adapter, Object object) {
+        int index = adapter.indexOf(object);
+        if (index >= 0) {
+            adapter.notifyArrayItemRangeChanged(index, 1);
+        }
+    }
+
+    private static String getSpeedString(int speed) {
+        switch (speed) {
+            case PLAYBACK_SPEED_INVALID:
+                return "PLAYBACK_SPEED_INVALID";
+            case PLAYBACK_SPEED_PAUSED:
+                return "PLAYBACK_SPEED_PAUSED";
+            case PLAYBACK_SPEED_NORMAL:
+                return "PLAYBACK_SPEED_NORMAL";
+            case PLAYBACK_SPEED_FAST_L0:
+                return "PLAYBACK_SPEED_FAST_L0";
+            case PLAYBACK_SPEED_FAST_L1:
+                return "PLAYBACK_SPEED_FAST_L1";
+            case PLAYBACK_SPEED_FAST_L2:
+                return "PLAYBACK_SPEED_FAST_L2";
+            case PLAYBACK_SPEED_FAST_L3:
+                return "PLAYBACK_SPEED_FAST_L3";
+            case PLAYBACK_SPEED_FAST_L4:
+                return "PLAYBACK_SPEED_FAST_L4";
+            case -PLAYBACK_SPEED_FAST_L0:
+                return "-PLAYBACK_SPEED_FAST_L0";
+            case -PLAYBACK_SPEED_FAST_L1:
+                return "-PLAYBACK_SPEED_FAST_L1";
+            case -PLAYBACK_SPEED_FAST_L2:
+                return "-PLAYBACK_SPEED_FAST_L2";
+            case -PLAYBACK_SPEED_FAST_L3:
+                return "-PLAYBACK_SPEED_FAST_L3";
+            case -PLAYBACK_SPEED_FAST_L4:
+                return "-PLAYBACK_SPEED_FAST_L4";
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if there is a valid media item.
+     */
+    public abstract boolean hasValidMedia();
+
+    /**
+     * Returns true if media is currently playing.
+     */
+    public abstract boolean isMediaPlaying();
+
+    /**
+     * Returns the title of the media item.
+     */
+    public abstract CharSequence getMediaTitle();
+
+    /**
+     * Returns the subtitle of the media item.
+     */
+    public abstract CharSequence getMediaSubtitle();
+
+    /**
+     * Returns the duration of the media item in milliseconds.
+     */
+    public abstract int getMediaDuration();
+
+    /**
+     * Returns a bitmap of the art for the media item.
+     */
+    public abstract Drawable getMediaArt();
+
+    /**
+     * Returns a bitmask of actions supported by the media player.
+     */
+    public abstract long getSupportedActions();
+
+    /**
+     * Returns the current playback speed.  When playing normally,
+     * {@link #PLAYBACK_SPEED_NORMAL} should be returned.
+     */
+    public abstract int getCurrentSpeedId();
+
+    /**
+     * Returns the current position of the media item in milliseconds.
+     */
+    public abstract int getCurrentPosition();
+
+    /**
+     * Start playback at the given speed.
+     * @param speed The desired playback speed.  For normal playback this will be
+     *              {@link #PLAYBACK_SPEED_NORMAL}; higher positive values for fast forward,
+     *              and negative values for rewind.
+     */
+    protected abstract void startPlayback(int speed);
+
+    /**
+     * Pause playback.
+     */
+    protected abstract void pausePlayback();
+
+    /**
+     * Skip to the next track.
+     */
+    protected abstract void skipToNext();
+
+    /**
+     * Skip to the previous track.
+     */
+    protected abstract void skipToPrevious();
+
+    /**
+     * Invoked when the playback controls row has changed.  The adapter containing this row
+     * should be notified.
+     */
+    protected abstract void onRowChanged(PlaybackControlsRow row);
+
+    /**
+     * Creates the primary action adapter.  May be overridden to add additional primary
+     * actions to the adapter.
+     */
+    protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
+            PresenterSelector presenterSelector) {
+        return new SparseArrayObjectAdapter(presenterSelector);
+    }
+
+    /**
+     * Must be called appropriately by a subclass when the playback state has changed.
+     */
+    protected void onStateChanged() {
+        if (DEBUG) Log.v(TAG, "onStateChanged");
+        // If a pending control button update is present, delay
+        // the update until the state settles.
+        if (!hasValidMedia()) {
+            return;
+        }
+        if (mHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE)) {
+            mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+            if (getCurrentSpeedId() != mPlaybackSpeed) {
+                if (DEBUG) Log.v(TAG, "Status expectation mismatch, delaying update");
+                mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
+                        UPDATE_PLAYBACK_STATE_DELAY_MS);
+            } else {
+                if (DEBUG) Log.v(TAG, "Update state matches expectation");
+                updatePlaybackState();
+            }
+        } else {
+            updatePlaybackState();
+        }
+    }
+
+    /**
+     * Must be called appropriately by a subclass when the metadata state has changed.
+     */
+    protected void onMetadataChanged() {
+        if (DEBUG) Log.v(TAG, "onMetadataChanged");
+        updateRowMetadata();
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
index 71a95e8..a5a7ccd 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
@@ -448,6 +448,10 @@
 
         @Override
         public boolean onPreDraw() {
+            if (getView() == null || getActivity() == null) {
+                mVerticalView.getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
             if (mState == STATE_INIT) {
                 setExpand(true);
                 mState = STATE_FIRST_DRAW;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
index 7f12aac..7390acf 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
@@ -450,6 +450,10 @@
 
         @Override
         public boolean onPreDraw() {
+            if (getView() == null || getActivity() == null) {
+                mVerticalView.getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
             if (mState == STATE_INIT) {
                 setExpand(true);
                 mState = STATE_FIRST_DRAW;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
index fc93625..d828963 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -34,6 +34,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.inputmethod.CompletionInfo;
 import android.widget.FrameLayout;
 import android.support.v17.leanback.R;
 
@@ -478,6 +479,17 @@
     }
 
     /**
+     * Displays the completions shown by the IME. An application may provide
+     * a list of query completions that the system will show in the IME.
+     *
+     * @param completions A list of completions to show in the IME. Setting to
+     *        null or empty will clear the list.
+     */
+    public void displayCompletions(CompletionInfo[] completions) {
+        mSearchBar.displayCompletions(completions);
+    }
+
+    /**
      * Sets this callback to have the fragment pass speech recognition requests
      * to the activity rather than using an internal recognizer.
      */
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
index e06f7e8..7ff364e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
@@ -36,6 +36,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.inputmethod.CompletionInfo;
 import android.widget.FrameLayout;
 import android.support.v17.leanback.R;
 
@@ -480,6 +481,17 @@
     }
 
     /**
+     * Displays the completions shown by the IME. An application may provide
+     * a list of query completions that the system will show in the IME.
+     *
+     * @param completions A list of completions to show in the IME. Setting to
+     *        null or empty will clear the list.
+     */
+    public void displayCompletions(CompletionInfo[] completions) {
+        mSearchBar.displayCompletions(completions);
+    }
+
+    /**
      * Sets this callback to have the fragment pass speech recognition requests
      * to the activity rather than using an internal recognizer.
      */
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
index 6b6cc2e..3e51989 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
@@ -15,6 +15,7 @@
 
 import android.support.annotation.ColorInt;
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.widget.BrowseFrameLayout;
 import android.support.v17.leanback.widget.OnChildLaidOutListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
@@ -38,7 +39,7 @@
  * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
  * an {@link ObjectAdapter}.
  */
-public class VerticalGridFragment extends BrandedFragment {
+public class VerticalGridFragment extends BaseFragment {
     private static final String TAG = "VerticalGridFragment";
     private static boolean DEBUG = false;
 
@@ -47,6 +48,7 @@
     private VerticalGridPresenter.ViewHolder mGridViewHolder;
     private OnItemViewSelectedListener mOnItemViewSelectedListener;
     private OnItemViewClickedListener mOnItemViewClickedListener;
+    private Object mSceneAfterEntranceTransition;
     private int mSelectedPosition = -1;
 
     /**
@@ -170,6 +172,13 @@
         gridDock.addView(mGridViewHolder.view);
         mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
 
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
+            @Override
+            public void run() {
+                setEntranceTransitionState(true);
+            }
+        });
+
         updateAdapter();
     }
 
@@ -183,7 +192,9 @@
     public void onStart() {
         super.onStart();
         setupFocusSearchListener();
-        mGridViewHolder.getGridView().requestFocus();
+        if (isEntranceTransitionEnabled()) {
+            setEntranceTransitionState(false);
+        }
     }
 
     @Override
@@ -210,4 +221,19 @@
             }
         }
     }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(getActivity(),
+                R.transition.lb_vertical_grid_entrance_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    void setEntranceTransitionState(boolean afterTransition) {
+        mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
index 0770761..eb0b337 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
@@ -17,6 +17,7 @@
 
 import android.support.annotation.ColorInt;
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.widget.BrowseFrameLayout;
 import android.support.v17.leanback.widget.OnChildLaidOutListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
@@ -40,7 +41,7 @@
  * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
  * an {@link ObjectAdapter}.
  */
-public class VerticalGridSupportFragment extends BrandedSupportFragment {
+public class VerticalGridSupportFragment extends BaseSupportFragment {
     private static final String TAG = "VerticalGridSupportFragment";
     private static boolean DEBUG = false;
 
@@ -49,6 +50,7 @@
     private VerticalGridPresenter.ViewHolder mGridViewHolder;
     private OnItemViewSelectedListener mOnItemViewSelectedListener;
     private OnItemViewClickedListener mOnItemViewClickedListener;
+    private Object mSceneAfterEntranceTransition;
     private int mSelectedPosition = -1;
 
     /**
@@ -172,6 +174,13 @@
         gridDock.addView(mGridViewHolder.view);
         mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
 
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
+            @Override
+            public void run() {
+                setEntranceTransitionState(true);
+            }
+        });
+
         updateAdapter();
     }
 
@@ -185,7 +194,9 @@
     public void onStart() {
         super.onStart();
         setupFocusSearchListener();
-        mGridViewHolder.getGridView().requestFocus();
+        if (isEntranceTransitionEnabled()) {
+            setEntranceTransitionState(false);
+        }
     }
 
     @Override
@@ -212,4 +223,19 @@
             }
         }
     }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(getActivity(),
+                R.transition.lb_vertical_grid_entrance_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    void setEntranceTransitionState(boolean afterTransition) {
+        mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java b/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
index f7451d4..47495cb 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
@@ -30,9 +30,9 @@
 
     static interface LeanbackTransitionHelperVersion {
 
-        public Object loadTitleInTransition(Context context, TransitionHelper helper);
+        public Object loadTitleInTransition(Context context);
 
-        public Object loadTitleOutTransition(Context context, TransitionHelper helper);
+        public Object loadTitleOutTransition(Context context);
     }
 
     /*
@@ -42,12 +42,12 @@
     static class LeanbackTransitionHelperKitKatImpl implements LeanbackTransitionHelperVersion {
 
         @Override
-        public Object loadTitleInTransition(Context context, TransitionHelper helper) {
+        public Object loadTitleInTransition(Context context) {
             return LeanbackTransitionHelperKitKat.loadTitleInTransition(context);
         }
 
         @Override
-        public Object loadTitleOutTransition(Context context, TransitionHelper helper) {
+        public Object loadTitleOutTransition(Context context) {
             return LeanbackTransitionHelperKitKat.loadTitleOutTransition(context);
         }
     }
@@ -58,13 +58,13 @@
     static class LeanbackTransitionHelperDefault implements LeanbackTransitionHelperVersion {
 
         @Override
-        public Object loadTitleInTransition(Context context, TransitionHelper helper) {
-            return helper.loadTransition(context, R.transition.lb_title_in);
+        public Object loadTitleInTransition(Context context) {
+            return TransitionHelper.loadTransition(context, R.transition.lb_title_in);
         }
 
         @Override
-        public Object loadTitleOutTransition(Context context, TransitionHelper helper) {
-            return helper.loadTransition(context, R.transition.lb_title_out);
+        public Object loadTitleOutTransition(Context context) {
+            return TransitionHelper.loadTransition(context, R.transition.lb_title_out);
         }
     }
 
@@ -81,11 +81,11 @@
         }
     }
 
-    static public Object loadTitleInTransition(Context context, TransitionHelper helper) {
-        return sImpl.loadTitleInTransition(context, helper);
+    static public Object loadTitleInTransition(Context context) {
+        return sImpl.loadTitleInTransition(context);
     }
 
-    static public Object loadTitleOutTransition(Context context, TransitionHelper helper) {
-        return sImpl.loadTitleOutTransition(context, helper);
+    static public Object loadTitleOutTransition(Context context) {
+        return sImpl.loadTitleOutTransition(context);
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
index 1c66d03..9420154 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
@@ -20,6 +20,8 @@
 import android.view.ViewGroup;
 import android.view.Window;
 
+import java.util.ArrayList;
+
 /**
  * Helper for view transitions.
  * @hide
@@ -34,8 +36,7 @@
     public static final int SLIDE_RIGHT = Gravity.RIGHT;
     public static final int SLIDE_BOTTOM = Gravity.BOTTOM;
 
-    private final static TransitionHelper sHelper = new TransitionHelper();
-    TransitionHelperVersionImpl mImpl;
+    private static TransitionHelperVersionImpl sImpl;
 
     /**
      * Gets whether the system supports Transition animations.
@@ -62,6 +63,16 @@
      */
     static interface TransitionHelperVersionImpl {
 
+        public void setEnterTransition(android.app.Fragment fragment, Object transition);
+
+        public void setExitTransition(android.app.Fragment fragment, Object transition);
+
+        public void setSharedElementEnterTransition(android.app.Fragment fragment,
+                Object transition);
+
+        public void addSharedElement(android.app.FragmentTransaction ft,
+                View view, String transitionName);
+
         public Object getSharedElementEnterTransition(Window window);
 
         public Object getSharedElementReturnTransition(Window window);
@@ -90,6 +101,8 @@
 
         public Object createChangeBounds(boolean reparent);
 
+        public Object createFadeAndShortSlide(int edge);
+
         public void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay);
 
         public void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay);
@@ -103,7 +116,9 @@
 
         public void addTransition(Object transitionSet, Object transition);
 
-        public void setTransitionListener(Object transition, TransitionListener listener);
+        public void addTransitionListener(Object transition, TransitionListener listener);
+
+        public void removeTransitionListener(Object transition, TransitionListener listener);
 
         public void runTransition(Object scene, Object transition);
 
@@ -130,15 +145,31 @@
         public Object createDefaultInterpolator(Context context);
 
         public Object loadTransition(Context context, int resId);
+
+        public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup);
     }
 
     /**
      * Interface used when we do not support Transition animations.
      */
-    private static final class TransitionHelperStubImpl implements TransitionHelperVersionImpl {
+    static class TransitionHelperStubImpl implements TransitionHelperVersionImpl {
 
         private static class TransitionStub {
-            TransitionListener mTransitionListener;
+            ArrayList<TransitionListener> mTransitionListeners;
+        }
+
+        public void setEnterTransition(android.app.Fragment fragment, Object transition) {
+        }
+
+        public void setExitTransition(android.app.Fragment fragment, Object transition) {
+        }
+
+        public void setSharedElementEnterTransition(android.app.Fragment fragment,
+                Object transition) {
+        }
+
+        public void addSharedElement(android.app.FragmentTransaction ft,
+                View view, String transitionName) {
         }
 
         @Override
@@ -202,6 +233,11 @@
         }
 
         @Override
+        public Object createFadeAndShortSlide(int edge) {
+            return new TransitionStub();
+        }
+
+        @Override
         public Object createSlide(int slideEdge) {
             return new TransitionStub();
         }
@@ -270,22 +306,38 @@
         }
 
         @Override
-        public void setTransitionListener(Object transition, TransitionListener listener) {
-            ((TransitionStub) transition).mTransitionListener = listener;
+        public void addTransitionListener(Object transition, TransitionListener listener) {
+            TransitionStub stub = (TransitionStub) transition;
+            if (stub.mTransitionListeners == null) {
+                stub.mTransitionListeners = new ArrayList<TransitionListener>();
+            }
+            stub.mTransitionListeners.add(listener);
+        }
+
+        @Override
+        public void removeTransitionListener(Object transition, TransitionListener listener) {
+            TransitionStub stub = (TransitionStub) transition;
+            if (stub.mTransitionListeners != null) {
+                stub.mTransitionListeners.remove(listener);
+            }
         }
 
         @Override
         public void runTransition(Object scene, Object transition) {
             TransitionStub transitionStub = (TransitionStub) transition;
-            if (transitionStub != null && transitionStub.mTransitionListener != null) {
-                transitionStub.mTransitionListener.onTransitionStart(transition);
+            if (transitionStub != null && transitionStub.mTransitionListeners != null) {
+                for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
+                    transitionStub.mTransitionListeners.get(i).onTransitionStart(transition);
+                }
             }
             Runnable r = ((Runnable) scene);
             if (r != null) {
                 r.run();
             }
-            if (transitionStub != null && transitionStub.mTransitionListener != null) {
-                transitionStub.mTransitionListener.onTransitionEnd(transition);
+            if (transitionStub != null && transitionStub.mTransitionListeners != null) {
+                for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
+                    transitionStub.mTransitionListeners.get(i).onTransitionEnd(transition);
+                }
             }
         }
 
@@ -306,52 +358,16 @@
         public Object loadTransition(Context context, int resId) {
             return new TransitionStub();
         }
+
+        @Override
+        public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+        }
     }
 
     /**
      * Implementation used on KitKat (and above).
      */
-    private static class TransitionHelperKitkatImpl implements TransitionHelperVersionImpl {
-
-        @Override
-        public Object getSharedElementEnterTransition(Window window) {
-            return null;
-        }
-
-        @Override
-        public Object getSharedElementReturnTransition(Window window) {
-            return null;
-        }
-
-        @Override
-        public Object getSharedElementExitTransition(Window window) {
-            return null;
-        }
-
-        @Override
-        public Object getSharedElementReenterTransition(Window window) {
-            return null;
-        }
-
-        @Override
-        public Object getEnterTransition(Window window) {
-            return null;
-        }
-
-        @Override
-        public Object getReturnTransition(Window window) {
-            return null;
-        }
-
-        @Override
-        public Object getExitTransition(Window window) {
-            return null;
-        }
-
-        @Override
-        public Object getReenterTransition(Window window) {
-            return null;
-        }
+    static class TransitionHelperKitkatImpl extends TransitionHelperStubImpl {
 
         @Override
         public Object createScene(ViewGroup sceneRoot, Runnable r) {
@@ -455,8 +471,13 @@
         }
 
         @Override
-        public void setTransitionListener(Object transition, TransitionListener listener) {
-            TransitionHelperKitkat.setTransitionListener(transition, listener);
+        public void addTransitionListener(Object transition, TransitionListener listener) {
+            TransitionHelperKitkat.addTransitionListener(transition, listener);
+        }
+
+        @Override
+        public void removeTransitionListener(Object transition, TransitionListener listener) {
+            TransitionHelperKitkat.removeTransitionListener(transition, listener);
         }
 
         @Override
@@ -485,7 +506,25 @@
         }
     }
 
-    private static final class TransitionHelperApi21Impl extends TransitionHelperKitkatImpl {
+    static final class TransitionHelperApi21Impl extends TransitionHelperKitkatImpl {
+
+        public void setEnterTransition(android.app.Fragment fragment, Object transition) {
+            TransitionHelperApi21.setEnterTransition(fragment, transition);
+        }
+
+        public void setExitTransition(android.app.Fragment fragment, Object transition) {
+            TransitionHelperApi21.setExitTransition(fragment, transition);
+        }
+
+        public void setSharedElementEnterTransition(android.app.Fragment fragment,
+                Object transition) {
+            TransitionHelperApi21.setSharedElementEnterTransition(fragment, transition);
+        }
+
+        public void addSharedElement(android.app.FragmentTransaction ft,
+                View view, String transitionName) {
+            TransitionHelperApi21.addSharedElement(ft, view, transitionName);
+        }
 
         @Override
         public Object getSharedElementEnterTransition(Window window) {
@@ -508,6 +547,11 @@
         }
 
         @Override
+        public Object createFadeAndShortSlide(int edge) {
+            return TransitionHelperApi21.createFadeAndShortSlide(edge);
+        }
+
+        @Override
         public Object getEnterTransition(Window window) {
             return TransitionHelperApi21.getEnterTransition(window);
         }
@@ -536,159 +580,207 @@
         public Object createDefaultInterpolator(Context context) {
             return TransitionHelperApi21.createDefaultInterpolator(context);
         }
-    }
 
-    /**
-     * Returns the TransitionHelper that can be used to perform Transition
-     * animations.
-     */
-    public static TransitionHelper getInstance() {
-        return sHelper;
-    }
-
-    private TransitionHelper() {
-        if (Build.VERSION.SDK_INT >= 21) {
-            mImpl = new TransitionHelperApi21Impl();
-        } else  if (systemSupportsTransitions()) {
-            mImpl = new TransitionHelperKitkatImpl();
-        } else {
-            mImpl = new TransitionHelperStubImpl();
+        @Override
+        public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+            TransitionHelperApi21.setTransitionGroup(viewGroup, transitionGroup);
         }
     }
 
-    public Object getSharedElementEnterTransition(Window window) {
-        return mImpl.getSharedElementEnterTransition(window);
+    static {
+        if (Build.VERSION.SDK_INT >= 21) {
+            sImpl = new TransitionHelperApi21Impl();
+        } else  if (systemSupportsTransitions()) {
+            sImpl = new TransitionHelperKitkatImpl();
+        } else {
+            sImpl = new TransitionHelperStubImpl();
+        }
     }
 
-    public Object getSharedElementReturnTransition(Window window) {
-        return mImpl.getSharedElementReturnTransition(window);
+    public static Object getSharedElementEnterTransition(Window window) {
+        return sImpl.getSharedElementEnterTransition(window);
     }
 
-    public Object getSharedElementExitTransition(Window window) {
-        return mImpl.getSharedElementExitTransition(window);
+    public static Object getSharedElementReturnTransition(Window window) {
+        return sImpl.getSharedElementReturnTransition(window);
     }
 
-    public Object getSharedElementReenterTransition(Window window) {
-        return mImpl.getSharedElementReenterTransition(window);
+    public static Object getSharedElementExitTransition(Window window) {
+        return sImpl.getSharedElementExitTransition(window);
     }
 
-    public Object getEnterTransition(Window window) {
-        return mImpl.getEnterTransition(window);
+    public static Object getSharedElementReenterTransition(Window window) {
+        return sImpl.getSharedElementReenterTransition(window);
     }
 
-    public Object getReturnTransition(Window window) {
-        return mImpl.getReturnTransition(window);
+    public static Object getEnterTransition(Window window) {
+        return sImpl.getEnterTransition(window);
     }
 
-    public Object getExitTransition(Window window) {
-        return mImpl.getExitTransition(window);
+    public static Object getReturnTransition(Window window) {
+        return sImpl.getReturnTransition(window);
     }
 
-    public Object getReenterTransition(Window window) {
-        return mImpl.getReenterTransition(window);
+    public static Object getExitTransition(Window window) {
+        return sImpl.getExitTransition(window);
     }
 
-    public Object createScene(ViewGroup sceneRoot, Runnable r) {
-        return mImpl.createScene(sceneRoot, r);
+    public static Object getReenterTransition(Window window) {
+        return sImpl.getReenterTransition(window);
     }
 
-    public Object createChangeBounds(boolean reparent) {
-        return mImpl.createChangeBounds(reparent);
+    public static Object createScene(ViewGroup sceneRoot, Runnable r) {
+        return sImpl.createScene(sceneRoot, r);
     }
 
-    public void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
-        mImpl.setChangeBoundsStartDelay(changeBounds, view, startDelay);
+    public static Object createChangeBounds(boolean reparent) {
+        return sImpl.createChangeBounds(reparent);
     }
 
-    public void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
-        mImpl.setChangeBoundsStartDelay(changeBounds, viewId, startDelay);
+    public static void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
+        sImpl.setChangeBoundsStartDelay(changeBounds, view, startDelay);
     }
 
-    public void setChangeBoundsStartDelay(Object changeBounds, String className, int startDelay) {
-        mImpl.setChangeBoundsStartDelay(changeBounds, className, startDelay);
+    public static void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
+        sImpl.setChangeBoundsStartDelay(changeBounds, viewId, startDelay);
     }
 
-    public void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
-        mImpl.setChangeBoundsDefaultStartDelay(changeBounds, startDelay);
+    public static void setChangeBoundsStartDelay(Object changeBounds, String className,
+            int startDelay) {
+        sImpl.setChangeBoundsStartDelay(changeBounds, className, startDelay);
     }
 
-    public Object createTransitionSet(boolean sequential) {
-        return mImpl.createTransitionSet(sequential);
+    public static void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
+        sImpl.setChangeBoundsDefaultStartDelay(changeBounds, startDelay);
     }
 
-    public Object createSlide(int slideEdge) {
-        return mImpl.createSlide(slideEdge);
+    public static Object createTransitionSet(boolean sequential) {
+        return sImpl.createTransitionSet(sequential);
     }
 
-    public Object createScale() {
-        return mImpl.createScale();
+    public static Object createSlide(int slideEdge) {
+        return sImpl.createSlide(slideEdge);
     }
 
-    public void addTransition(Object transitionSet, Object transition) {
-        mImpl.addTransition(transitionSet, transition);
+    public static Object createScale() {
+        return sImpl.createScale();
     }
 
-    public void exclude(Object transition, int targetId, boolean exclude) {
-        mImpl.exclude(transition, targetId, exclude);
+    public static void addTransition(Object transitionSet, Object transition) {
+        sImpl.addTransition(transitionSet, transition);
     }
 
-    public void exclude(Object transition, View targetView, boolean exclude) {
-        mImpl.exclude(transition, targetView, exclude);
+    public static void exclude(Object transition, int targetId, boolean exclude) {
+        sImpl.exclude(transition, targetId, exclude);
     }
 
-    public void excludeChildren(Object transition, int targetId, boolean exclude) {
-        mImpl.excludeChildren(transition, targetId, exclude);
+    public static void exclude(Object transition, View targetView, boolean exclude) {
+        sImpl.exclude(transition, targetView, exclude);
     }
 
-    public void excludeChildren(Object transition, View targetView, boolean exclude) {
-        mImpl.excludeChildren(transition, targetView, exclude);
+    public static void excludeChildren(Object transition, int targetId, boolean exclude) {
+        sImpl.excludeChildren(transition, targetId, exclude);
     }
 
-    public void include(Object transition, int targetId) {
-        mImpl.include(transition, targetId);
+    public static void excludeChildren(Object transition, View targetView, boolean exclude) {
+        sImpl.excludeChildren(transition, targetView, exclude);
     }
 
-    public void include(Object transition, View targetView) {
-        mImpl.include(transition, targetView);
+    public static void include(Object transition, int targetId) {
+        sImpl.include(transition, targetId);
     }
 
-    public void setStartDelay(Object transition, long startDelay) {
-        mImpl.setStartDelay(transition, startDelay);
+    public static void include(Object transition, View targetView) {
+        sImpl.include(transition, targetView);
     }
 
-    public void setDuration(Object transition, long duration) {
-        mImpl.setDuration(transition, duration);
+    public static void setStartDelay(Object transition, long startDelay) {
+        sImpl.setStartDelay(transition, startDelay);
     }
 
-    public Object createAutoTransition() {
-        return mImpl.createAutoTransition();
+    public static void setDuration(Object transition, long duration) {
+        sImpl.setDuration(transition, duration);
     }
 
-    public Object createFadeTransition(int fadeMode) {
-        return mImpl.createFadeTransition(fadeMode);
+    public static Object createAutoTransition() {
+        return sImpl.createAutoTransition();
     }
 
-    public void setTransitionListener(Object transition, TransitionListener listener) {
-        mImpl.setTransitionListener(transition, listener);
+    public static Object createFadeTransition(int fadeMode) {
+        return sImpl.createFadeTransition(fadeMode);
     }
 
-    public void runTransition(Object scene, Object transition) {
-        mImpl.runTransition(scene, transition);
+    public static void addTransitionListener(Object transition, TransitionListener listener) {
+        sImpl.addTransitionListener(transition, listener);
     }
 
-    public void setInterpolator(Object transition, Object timeInterpolator) {
-        mImpl.setInterpolator(transition, timeInterpolator);
+    public static void removeTransitionListener(Object transition, TransitionListener listener) {
+        sImpl.removeTransitionListener(transition, listener);
     }
 
-    public void addTarget(Object transition, View view) {
-        mImpl.addTarget(transition, view);
+    public static void runTransition(Object scene, Object transition) {
+        sImpl.runTransition(scene, transition);
     }
 
-    public Object createDefaultInterpolator(Context context) {
-        return mImpl.createDefaultInterpolator(context);
+    public static void setInterpolator(Object transition, Object timeInterpolator) {
+        sImpl.setInterpolator(transition, timeInterpolator);
     }
 
-    public Object loadTransition(Context context, int resId) {
-        return mImpl.loadTransition(context, resId);
+    public static void addTarget(Object transition, View view) {
+        sImpl.addTarget(transition, view);
+    }
+
+    public static Object createDefaultInterpolator(Context context) {
+        return sImpl.createDefaultInterpolator(context);
+    }
+
+    public static Object loadTransition(Context context, int resId) {
+        return sImpl.loadTransition(context, resId);
+    }
+
+    public static void setEnterTransition(android.app.Fragment fragment, Object transition) {
+        sImpl.setEnterTransition(fragment, transition);
+    }
+
+    public static void setExitTransition(android.app.Fragment fragment, Object transition) {
+        sImpl.setExitTransition(fragment, transition);
+    }
+
+    public static void setSharedElementEnterTransition(android.app.Fragment fragment,
+            Object transition) {
+        sImpl.setSharedElementEnterTransition(fragment, transition);
+    }
+
+    public static void addSharedElement(android.app.FragmentTransaction ft,
+            View view, String transitionName) {
+        sImpl.addSharedElement(ft, view, transitionName);
+    }
+
+    public static void setEnterTransition(android.support.v4.app.Fragment fragment,
+            Object transition) {
+        fragment.setEnterTransition(transition);
+    }
+
+    public static void setExitTransition(android.support.v4.app.Fragment fragment,
+            Object transition) {
+        fragment.setExitTransition(transition);
+    }
+
+    public static void setSharedElementEnterTransition(android.support.v4.app.Fragment fragment,
+            Object transition) {
+        fragment.setSharedElementEnterTransition(transition);
+    }
+
+    public static void addSharedElement(android.support.v4.app.FragmentTransaction ft,
+            View view, String transitionName) {
+        ft.addSharedElement(view, transitionName);
+    }
+
+    public static Object createFadeAndShortSlide(int edge) {
+        return sImpl.createFadeAndShortSlide(edge);
+    }
+
+    public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+        sImpl.setTransitionGroup(viewGroup, transitionGroup);
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
index 614f12b..085aac3 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
 import android.support.v17.leanback.R;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -154,6 +155,14 @@
 
         try {
             mCardType = a.getInteger(R.styleable.lbBaseCardView_cardType, CARD_TYPE_MAIN_ONLY);
+            Drawable cardForeground = a.getDrawable(R.styleable.lbBaseCardView_cardForeground);
+            if (cardForeground != null) {
+                setForeground(cardForeground);
+            }
+            Drawable cardBackground = a.getDrawable(R.styleable.lbBaseCardView_cardBackground);
+            if (cardBackground != null) {
+                setBackground(cardBackground);
+            }
             mInfoVisibility = a.getInteger(R.styleable.lbBaseCardView_infoVisibility,
                     CARD_REGION_VISIBLE_ACTIVATED);
             mExtraVisibility = a.getInteger(R.styleable.lbBaseCardView_extraVisibility,
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
index 93a454e..73e5b40 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
@@ -23,6 +23,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.support.v7.widget.SimpleItemAnimator;
 
 /**
  * An abstract base class for vertically and horizontally scrolling lists. The items come
@@ -201,7 +202,7 @@
         // Disable change animation by default on leanback.
         // Change animation will create a new view and cause undesired
         // focus animation between the old view and new view.
-        getItemAnimator().setSupportsChangeAnimations(false);
+        ((SimpleItemAnimator)getItemAnimator()).setSupportsChangeAnimations(false);
         super.setRecyclerListener(new RecyclerView.RecyclerListener() {
             @Override
             public void onViewRecycled(RecyclerView.ViewHolder holder) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java b/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java
new file mode 100644
index 0000000..627bbd4
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Checkable;
+import android.widget.ImageView;
+
+/**
+ * ImageView that supports Checkable states.
+ */
+class CheckableImageView extends ImageView implements Checkable {
+
+    private boolean mChecked;
+
+    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
+
+    public CheckableImageView(Context context) {
+        this(context, null);
+    }
+
+    public CheckableImageView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CheckableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    public int[] onCreateDrawableState(final int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+        if (isChecked()) {
+            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+        }
+        return drawableState;
+    }
+
+    @Override
+    public void toggle() {
+        setChecked(!mChecked);
+    }
+
+    @Override
+    public boolean isChecked() {
+        return mChecked;
+    }
+
+    @Override
+    public void setChecked(final boolean checked) {
+        if (mChecked != checked) {
+            mChecked = checked;
+            refreshDrawableState();
+        }
+    }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
index 410aa28..cac7d9e 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
@@ -232,11 +232,10 @@
                     Log.d(TAG, "setTransitionName "+mViewHolder.mOverviewFrame);
                 }
                 ViewCompat.setTransitionName(mViewHolder.mOverviewFrame, mSharedElementName);
-                final TransitionHelper transitionHelper = TransitionHelper.getInstance();
-                Object transition = transitionHelper.getSharedElementEnterTransition(
+                Object transition = TransitionHelper.getSharedElementEnterTransition(
                         mActivityToRunTransition.getWindow());
                 if (transition != null) {
-                    transitionHelper.setTransitionListener(transition, new TransitionListener() {
+                    TransitionHelper.addTransitionListener(transition, new TransitionListener() {
                         @Override
                         public void onTransitionEnd(Object transition) {
                             if (DEBUG) {
@@ -247,7 +246,7 @@
                             if (mViewHolder.mActionsRow.isFocused()) {
                                 mViewHolder.mActionsRow.requestFocus();
                             }
-                            transitionHelper.setTransitionListener(transition, null);
+                            TransitionHelper.removeTransitionListener(transition, this);
                         }
                     });
                 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
index 48829eb..87bbbd4 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
@@ -85,7 +85,7 @@
                 mWrapper = null;
             }
             mAnimator.setTimeListener(this);
-            if (mWrapper != null && useDimmer) {
+            if (useDimmer) {
                 mDimmer = ColorOverlayDimmer.createDefault(view.getContext());
             } else {
                 mDimmer = null;
@@ -99,9 +99,16 @@
             mView.setScaleY(scale);
             if (mWrapper != null) {
                 mWrapper.setShadowFocusLevel(level);
-                if (mDimmer != null) {
-                    mDimmer.setActiveLevel(level);
-                    mWrapper.setOverlayColor(mDimmer.getPaint().getColor());
+            } else {
+                ShadowOverlayHelper.setNoneWrapperShadowFocusLevel(mView, level);
+            }
+            if (mDimmer != null) {
+                mDimmer.setActiveLevel(level);
+                int color = mDimmer.getPaint().getColor();
+                if (mWrapper != null) {
+                    mWrapper.setOverlayColor(color);
+                } else {
+                    ShadowOverlayHelper.setNoneWrapperOverlayColor(mView, color);
                 }
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
new file mode 100644
index 0000000..c9bed58
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
@@ -0,0 +1,78 @@
+package android.support.v17.leanback.widget;
+
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewGroup;
+
+final class ForegroundHelper {
+
+    final static ForegroundHelper sInstance = new ForegroundHelper();
+    ForegroundHelperVersionImpl mImpl;
+
+    /**
+     * Interface implemented by classes that support Shadow.
+     */
+    static interface ForegroundHelperVersionImpl {
+
+        public void setForeground(View view, Drawable drawable);
+
+        public Drawable getForeground(View view);
+    }
+
+    /**
+     * Implementation used on api 23 (and above).
+     */
+    private static final class ForegroundHelperApi23Impl implements ForegroundHelperVersionImpl {
+        @Override
+        public void setForeground(View view, Drawable drawable) {
+            ForegroundHelperApi23.setForeground(view, drawable);
+        }
+
+        @Override
+        public Drawable getForeground(View view) {
+            return ForegroundHelperApi23.getForeground(view);
+        }
+    }
+
+    /**
+     * Stub implementation
+     */
+    private static final class ForegroundHelperStubImpl implements ForegroundHelperVersionImpl {
+        @Override
+        public void setForeground(View view, Drawable drawable) {
+        }
+
+        @Override
+        public Drawable getForeground(View view) {
+            return null;
+        }
+    }
+
+    private ForegroundHelper() {
+        if (supportsForeground()) {
+            mImpl = new ForegroundHelperApi23Impl();
+        } else {
+            mImpl = new ForegroundHelperStubImpl();
+        }
+    }
+
+    public static ForegroundHelper getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * Returns true if view.setForeground() is supported.
+     */
+    public static boolean supportsForeground() {
+        return Build.VERSION.SDK_INT >= 23;
+    }
+
+    public Drawable getForeground(View view) {
+        return mImpl.getForeground(view);
+    }
+
+    public void setForeground(View view, Drawable drawable) {
+        mImpl.setForeground(view, drawable);
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java b/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java
index 8bd0007..1c5dcb5 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java
@@ -26,47 +26,15 @@
 public interface FragmentAnimationProvider {
 
     /**
-     * Animates the entry of the fragment in the case where the activity is first being presented.
+     * Animates the fragment in response to the IME appearing.
      * @param animators A list of animations to which this provider's animations should be added.
      */
-    public abstract void onActivityEnter(@NonNull List<Animator> animators);
+    public abstract void onImeAppearing(@NonNull List<Animator> animators);
 
     /**
-     * Animates the exit of the fragment in the case where the activity is about to pause.
+     * Animates the fragment in response to the IME disappearing.
      * @param animators A list of animations to which this provider's animations should be added.
      */
-    public abstract void onActivityExit(@NonNull List<Animator> animators);
-
-    /**
-     * Animates the entry of the fragment in the case where there is a previous step fragment
-     * participating in the animation. Entry occurs when the fragment is preparing to be shown
-     * as it is pushed onto the back stack.
-     * @param animators A list of animations to which this provider's animations should be added.
-     */
-    public abstract void onFragmentEnter(@NonNull List<Animator> animators);
-
-    /**
-     * Animates the exit of the fragment in the case where there is a previous step fragment
-     * participating in the animation. Exit occurs when the fragment is preparing to be removed,
-     * hidden, or detached due to pushing another fragment onto the back stack.
-     * @param animators A list of animations to which this provider's animations should be added.
-     */
-    public abstract void onFragmentExit(@NonNull List<Animator> animators);
-
-    /**
-     * Animates the re-entry of the fragment in the case where there is a previous step fragment
-     * participating in the animation. Re-entry occurs when the fragment is preparing to be shown
-     * due to popping the back stack.
-     * @param animators A list of animations to which this provider's animations should be added.
-     */
-    public abstract void onFragmentReenter(@NonNull List<Animator> animators);
-
-    /**
-     * Animates the return of the fragment in the case where there is a previous step fragment
-     * participating in the animation. Return occurs when the fragment is preparing to be removed,
-     * hidden, or detached due to popping the back stack.
-     * @param animators A list of animations to which this provider's animations should be added.
-     */
-    public abstract void onFragmentReturn(@NonNull List<Animator> animators);
+    public abstract void onImeDisappearing(@NonNull List<Animator> animators);
 
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
index c4418c1..7c9d5db 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
@@ -528,19 +528,6 @@
         mListener = listener;
     }
 
-    private int getDefaultBackgroundColor(Context context) {
-        TypedValue outValue = new TypedValue();
-        if (context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
-            return context.getResources().getColor(outValue.resourceId);
-        }
-        return context.getResources().getColor(R.color.lb_default_brand_color);
-    }
-
-    private int getDefaultActionsBackgroundColor(Context context) {
-        int c = getDefaultBackgroundColor(context);
-        return Color.argb(Color.alpha(c), Color.red(c) / 2, Color.green(c) / 2, Color.blue(c) / 2);
-    }
-
     /**
      * Get resource id to inflate the layout.  The layout must match {@link #STATE_HALF}
      */
@@ -558,13 +545,13 @@
 
         vh.mActionBridgeAdapter = new ActionsItemBridgeAdapter(vh);
         final View overview = vh.mOverviewFrame;
-        final int bgColor = mBackgroundColorSet ? mBackgroundColor :
-                getDefaultBackgroundColor(overview.getContext());
-        overview.setBackgroundColor(bgColor);
-        final int actionBgColor = mActionsBackgroundColorSet ? mActionsBackgroundColor :
-                getDefaultActionsBackgroundColor(overview.getContext());
-        overview.findViewById(R.id.details_overview_actions_background)
-                .setBackgroundColor(actionBgColor);
+        if (mBackgroundColorSet) {
+            overview.setBackgroundColor(mBackgroundColor);
+        }
+        if (mActionsBackgroundColorSet) {
+            overview.findViewById(R.id.details_overview_actions_background)
+                    .setBackgroundColor(mActionsBackgroundColor);
+        }
         RoundedRectHelper.getInstance().setClipToRoundedOutline(overview, true);
 
         if (!getSelectEffectEnabled()) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
index 857c4d9..a9fe9ec 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
@@ -76,8 +76,7 @@
         if (DEBUG) {
             Log.d(TAG, "postponeEnterTransition " + mActivityToRunTransition);
         }
-        Object transition = TransitionHelper.getInstance()
-                .getSharedElementEnterTransition(activity.getWindow());
+        Object transition = TransitionHelper.getSharedElementEnterTransition(activity.getWindow());
         setAutoStartSharedElementTransition(transition != null);
         ActivityCompat.postponeEnterTransition(mActivityToRunTransition);
         if (timeoutMs > 0) {
@@ -140,11 +139,10 @@
                 }
                 ViewCompat.setTransitionName(mViewHolder.getLogoViewHolder().view,
                         mSharedElementName);
-                final TransitionHelper transitionHelper = TransitionHelper.getInstance();
-                Object transition = transitionHelper.getSharedElementEnterTransition(
+                Object transition = TransitionHelper.getSharedElementEnterTransition(
                         mActivityToRunTransition.getWindow());
                 if (transition != null) {
-                    transitionHelper.setTransitionListener(transition, new TransitionListener() {
+                    TransitionHelper.addTransitionListener(transition, new TransitionListener() {
                         @Override
                         public void onTransitionEnd(Object transition) {
                             if (DEBUG) {
@@ -155,7 +153,7 @@
                             if (mViewHolder.getActionsRow().isFocused()) {
                                 mViewHolder.getActionsRow().requestFocus();
                             }
-                            transitionHelper.setTransitionListener(transition, null);
+                            TransitionHelper.removeTransitionListener(transition, this);
                         }
                     });
                 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index 10c7e3e..20d54e2 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -58,7 +58,7 @@
       * - Saves optical bounds insets.
       * - Caches focus align view center.
       */
-    static class LayoutParams extends RecyclerView.LayoutParams {
+    final static class LayoutParams extends RecyclerView.LayoutParams {
 
         // For placement
         private int mLeftInset;
@@ -128,6 +128,32 @@
             return view.getHeight() - mTopInset - mBottomInset;
         }
 
+        int getDecoratedOpticalLeftWithMargin(RecyclerView.LayoutManager lm, View view) {
+            return lm.getDecoratedLeft(view) + mLeftInset - leftMargin;
+        }
+
+        int getDecoratedOpticalTopWithMargin(RecyclerView.LayoutManager lm, View view) {
+            return lm.getDecoratedTop(view) + mTopInset - topMargin;
+        }
+
+        int getDecoratedOpticalRightWithMargin(RecyclerView.LayoutManager lm, View view) {
+            return lm.getDecoratedRight(view) - mRightInset + rightMargin;
+        }
+
+        int getDecoratedOpticalBottomWithMargin(RecyclerView.LayoutManager lm, View view) {
+            return lm.getDecoratedBottom(view) - mBottomInset + bottomMargin;
+        }
+
+        int getDecoratedOpticalWidthWithMargin(RecyclerView.LayoutManager lm, View view) {
+            return lm.getDecoratedRight(view) - lm.getDecoratedLeft(view)
+                    - mLeftInset - mRightInset + leftMargin + rightMargin;
+        }
+
+        int getDecoratedOpticalHeightWithMargin(RecyclerView.LayoutManager lm, View view) {
+            return lm.getDecoratedBottom(view) - lm.getDecoratedTop(view)
+                    - mTopInset - mBottomInset + topMargin + bottomMargin;
+        }
+
         int getOpticalLeftInset() {
             return mLeftInset;
         }
@@ -199,9 +225,18 @@
 
         @Override
         protected void onStop() {
-            // onTargetFound() may not be called if we hit the "wall" first.
+            // onTargetFound() may not be called if we hit the "wall" first or get cancelled.
             View targetView = findViewByPosition(getTargetPosition());
-            if (hasFocus() && targetView != null) {
+            if (targetView == null) {
+                if (getTargetPosition() >= 0) {
+                    // if smooth scroller is stopped without target, immediately jumps
+                    // to the target position.
+                    scrollToSelection(mBaseGridView, getTargetPosition(), 0, false, 0);
+                }
+                super.onStop();
+                return;
+            }
+            if (hasFocus()) {
                 mInSelection = true;
                 targetView.requestFocus();
                 mInSelection = false;
@@ -391,6 +426,8 @@
     private RecyclerView.State mState;
     private RecyclerView.Recycler mRecycler;
 
+    private static final Rect sTempRect = new Rect();
+
     private boolean mInLayout;
     private boolean mInScroll;
     private boolean mInFastRelayout;
@@ -913,16 +950,21 @@
     }
 
     private int getViewMin(View v) {
-        return (mOrientation == HORIZONTAL) ? getOpticalLeft(v) : getOpticalTop(v);
+        LayoutParams lp = (LayoutParams) v.getLayoutParams();
+        return (mOrientation == HORIZONTAL) ? lp.getDecoratedOpticalLeftWithMargin(this, v)
+                : lp.getDecoratedOpticalTopWithMargin(this, v);
     }
 
     private int getViewMax(View v) {
-        return (mOrientation == HORIZONTAL) ? getOpticalRight(v) : getOpticalBottom(v);
+        LayoutParams lp = (LayoutParams) v.getLayoutParams();
+        return (mOrientation == HORIZONTAL) ? lp.getDecoratedOpticalRightWithMargin(this, v)
+                : lp.getDecoratedOpticalBottomWithMargin(this, v);
     }
 
     private int getViewPrimarySize(View view) {
         LayoutParams p = (LayoutParams) view.getLayoutParams();
-        return mOrientation == HORIZONTAL ? p.getOpticalWidth(view) : p.getOpticalHeight(view);
+        return mOrientation == HORIZONTAL ? p.getDecoratedOpticalWidthWithMargin(this, view)
+                : p.getDecoratedOpticalHeightWithMargin(this, view);
     }
 
     private int getViewCenter(View view) {
@@ -1056,18 +1098,33 @@
         return getRowStartSecondary(rightmostIndex) + getRowSizeSecondary(rightmostIndex);
     }
 
+    int getDecoratedMeasuredWidthWithMargin(View v) {
+        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+        return getDecoratedMeasuredWidth(v) + lp.leftMargin + lp.rightMargin;
+    }
+
+    int getDecoratedMeasuredHeightWithMargin(View v) {
+        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+        return getDecoratedMeasuredHeight(v) + lp.topMargin + lp.bottomMargin;
+    }
+
     private void measureScrapChild(int position, int widthSpec, int heightSpec,
             int[] measuredDimension) {
         View view = mRecycler.getViewForPosition(position);
         if (view != null) {
-            LayoutParams p = (LayoutParams) view.getLayoutParams();
+            final LayoutParams p = (LayoutParams) view.getLayoutParams();
+            calculateItemDecorationsForChild(view, sTempRect);
+            int widthUsed = p.leftMargin + p.rightMargin + sTempRect.left + sTempRect.right;
+            int heightUsed = p.topMargin + p.bottomMargin + sTempRect.top + sTempRect.bottom;
+
             int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
-                    getPaddingLeft() + getPaddingRight(), p.width);
+                    getPaddingLeft() + getPaddingRight() + widthUsed, p.width);
             int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
-                    getPaddingTop() + getPaddingBottom(), p.height);
+                    getPaddingTop() + getPaddingBottom() + heightUsed, p.height);
             view.measure(childWidthSpec, childHeightSpec);
-            measuredDimension[0] = view.getMeasuredWidth();
-            measuredDimension[1] = view.getMeasuredHeight();
+
+            measuredDimension[0] = getDecoratedMeasuredWidthWithMargin(view);
+            measuredDimension[1] = getDecoratedMeasuredHeightWithMargin(view);
             mRecycler.recycleView(view);
         }
     }
@@ -1100,7 +1157,8 @@
                         measureChild(view);
                     }
                     final int secondarySize = mOrientation == HORIZONTAL ?
-                            view.getMeasuredHeight() : view.getMeasuredWidth();
+                            getDecoratedMeasuredHeightWithMargin(view)
+                            : getDecoratedMeasuredWidthWithMargin(view);
                     if (secondarySize > rowSize) {
                         rowSize = secondarySize;
                     }
@@ -1229,14 +1287,8 @@
         } else {
             switch (modeSecondary) {
             case MeasureSpec.UNSPECIFIED:
-                if (mRowSizeSecondaryRequested == 0) {
-                    if (mOrientation == HORIZONTAL) {
-                        throw new IllegalStateException("Must specify rowHeight or view height");
-                    } else {
-                        throw new IllegalStateException("Must specify columnWidth or view width");
-                    }
-                }
-                mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
+                mFixedRowSizeSecondary = mRowSizeSecondaryRequested == 0 ?
+                        sizeSecondary - paddingSecondary: mRowSizeSecondaryRequested;
                 mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
                 measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mMarginSecondary
                     * (mNumRows - 1) + paddingSecondary;
@@ -1287,7 +1339,11 @@
 
     private void measureChild(View child) {
         if (TRACE) TraceHelper.beginSection("measureChild");
-        final ViewGroup.LayoutParams lp = child.getLayoutParams();
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        calculateItemDecorationsForChild(child, sTempRect);
+        int widthUsed = lp.leftMargin + lp.rightMargin + sTempRect.left + sTempRect.right;
+        int heightUsed = lp.topMargin + lp.bottomMargin + sTempRect.top + sTempRect.bottom;
+
         final int secondarySpec = (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT) ?
                 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) :
                 MeasureSpec.makeMeasureSpec(mFixedRowSizeSecondary, MeasureSpec.EXACTLY);
@@ -1295,14 +1351,12 @@
 
         if (mOrientation == HORIZONTAL) {
             widthSpec = ViewGroup.getChildMeasureSpec(
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
-                    0, lp.width);
-            heightSpec = ViewGroup.getChildMeasureSpec(secondarySpec, 0, lp.height);
+                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), widthUsed, lp.width);
+            heightSpec = ViewGroup.getChildMeasureSpec(secondarySpec, heightUsed, lp.height);
         } else {
             heightSpec = ViewGroup.getChildMeasureSpec(
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
-                    0, lp.height);
-            widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, 0, lp.width);
+                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightUsed, lp.height);
+            widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, widthUsed, lp.width);
         }
         child.measure(widthSpec, heightSpec);
         if (DEBUG) Log.v(getTag(), "measureChild secondarySpec " + Integer.toHexString(secondarySpec) +
@@ -1395,7 +1449,8 @@
                 measureChild(v);
             }
             item[0] = v;
-            return mOrientation == HORIZONTAL ? v.getMeasuredWidth() : v.getMeasuredHeight();
+            return mOrientation == HORIZONTAL ? getDecoratedMeasuredWidthWithMargin(v)
+                    : getDecoratedMeasuredHeightWithMargin(v);
         }
 
         @Override
@@ -1476,8 +1531,8 @@
 
     private void layoutChild(int rowIndex, View v, int start, int end, int startSecondary) {
         if (TRACE) TraceHelper.beginSection("layoutChild");
-        int sizeSecondary = mOrientation == HORIZONTAL ? v.getMeasuredHeight()
-                : v.getMeasuredWidth();
+        int sizeSecondary = mOrientation == HORIZONTAL ? getDecoratedMeasuredHeightWithMargin(v)
+                : getDecoratedMeasuredWidthWithMargin(v);
         if (mFixedRowSizeSecondary > 0) {
             sizeSecondary = Math.min(sizeSecondary, mFixedRowSizeSecondary);
         }
@@ -1507,7 +1562,9 @@
             bottom = end;
             right = startSecondary + sizeSecondary;
         }
-        v.layout(left, top, right, bottom);
+        LayoutParams params = (LayoutParams) v.getLayoutParams();
+        layoutDecorated(v, left + params.leftMargin, top + params.topMargin,
+                right - params.rightMargin, bottom - params.bottomMargin);
         updateChildOpticalInsets(v, left, top, right, bottom);
         updateChildAlignments(v);
         if (TRACE) TraceHelper.endSection();
@@ -1624,10 +1681,10 @@
                 measureChild(view);
             }
             if (mOrientation == HORIZONTAL) {
-                primarySize = view.getMeasuredWidth();
+                primarySize = getDecoratedMeasuredWidthWithMargin(view);
                 end = start + primarySize;
             } else {
-                primarySize = view.getMeasuredHeight();
+                primarySize = getDecoratedMeasuredHeightWithMargin(view);
                 end = start + primarySize;
             }
             layoutChild(location.row, view, start, end, startSecondary);
@@ -1716,6 +1773,11 @@
         mFocusPositionOffset = 0;
         saveContext(recycler, state);
 
+        View savedFocusView = findViewByPosition(mFocusPosition);
+        int savedFocusPos = mFocusPosition;
+        int savedSubFocusPos = mSubFocusPosition;
+        boolean hadFocus = mBaseGridView.hasFocus();
+
         // Track the old focus view so we can adjust our system scroll position
         // so that any scroll animations happening now will remain valid.
         // We must use same delta in Pre Layout (if prelayout exists) and second layout.
@@ -1724,17 +1786,14 @@
         if (mFocusPosition != NO_POSITION && scrollToFocus
                 && mBaseGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
             // FIXME: we should get the remaining scroll animation offset from RecyclerView
-            View focusView = findViewByPosition(mFocusPosition);
-            if (focusView != null) {
-                if (getScrollPosition(focusView, focusView.findFocus(), sTwoInts)) {
+            if (savedFocusView != null) {
+                if (getScrollPosition(savedFocusView, savedFocusView.findFocus(), sTwoInts)) {
                     delta = sTwoInts[0];
                     deltaSecondary = sTwoInts[1];
                 }
             }
         }
 
-        boolean hadFocus = mBaseGridView.hasFocus();
-        int savedFocusPos = mFocusPosition;
         if (mInFastRelayout = layoutInit()) {
             fastRelayout();
             // appends items till focus position.
@@ -1802,7 +1861,8 @@
         }
 
         // For fastRelayout, only dispatch event when focus position changes.
-        if (mInFastRelayout && mFocusPosition != savedFocusPos) {
+        if (mInFastRelayout && (mFocusPosition != savedFocusPos || mSubFocusPosition !=
+                savedFocusPos || findViewByPosition(mFocusPosition) != savedFocusView)) {
             dispatchChildSelected();
         } else if (!mInFastRelayout && mInLayoutSearchFocus) {
             // For full layout we dispatchChildSelected() in createItem() unless searched all
@@ -1968,7 +2028,7 @@
         int pos = sTwoInts[1];
         int savedMaxEdge = mWindowAlignment.mainAxis().getMaxEdge();
         mWindowAlignment.mainAxis().setMaxEdge(maxEdge);
-        int maxScroll = getPrimarySystemScrollPosition(findViewByPosition(pos));
+        int maxScroll = getPrimarySystemScrollPositionOfChildMax(findViewByPosition(pos));
         mWindowAlignment.mainAxis().setMaxEdge(savedMaxEdge);
 
         if (highAvailable) {
@@ -2319,6 +2379,16 @@
         return mWindowAlignment.mainAxis().getSystemScrollPos(viewCenterPrimary, isMin, isMax);
     }
 
+    private int getPrimarySystemScrollPositionOfChildMax(View view) {
+        int scrollPosition = getPrimarySystemScrollPosition(view);
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        int[] multipleAligns = lp.getAlignMultiple();
+        if (multipleAligns != null && multipleAligns.length > 0) {
+            scrollPosition += multipleAligns[multipleAligns.length - 1] - multipleAligns[0];
+        }
+        return scrollPosition;
+    }
+
     /**
      * Get adjusted primary position for a given childView (if there is multiple ItemAlignment defined
      * on the view).
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
index 8d12510..3fcdbba 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
@@ -54,11 +54,8 @@
  * </ul><p>
  * View IDs are allowed to be missing, in which case the corresponding views will be null.
  *
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceEntryAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepEntryAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepExitAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReentryAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReturnAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceContainerStyle
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceTitleStyle
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceDescriptionStyle
@@ -176,6 +173,16 @@
     }
 
     /**
+     * Called when destroy the View created by GuidanceStylist.
+     */
+    public void onDestroyView() {
+        mBreadcrumbView = null;
+        mDescriptionView = null;
+        mIconView = null;
+        mTitleView = null;
+    }
+
+    /**
      * Provides the resource ID of the layout defining the guidance view. Subclasses may override
      * to provide their own customized layouts. The base implementation returns
      * {@link android.support.v17.leanback.R.layout#lb_guidance}. If overridden, the substituted
@@ -223,61 +230,22 @@
      * {@inheritDoc}
      */
     @Override
-    public void onActivityEnter(@NonNull List<Animator> animators) {
-        addAnimator(animators, mTitleView, R.attr.guidanceEntryAnimation);
-        addAnimator(animators, mBreadcrumbView, R.attr.guidanceEntryAnimation);
-        addAnimator(animators, mDescriptionView, R.attr.guidanceEntryAnimation);
-        addAnimator(animators, mIconView, R.attr.guidanceEntryAnimation);
+    public void onImeAppearing(@NonNull List<Animator> animators) {
+        addAnimator(animators, mTitleView, R.attr.guidedStepImeAppearingAnimation);
+        addAnimator(animators, mBreadcrumbView, R.attr.guidedStepImeAppearingAnimation);
+        addAnimator(animators, mDescriptionView, R.attr.guidedStepImeAppearingAnimation);
+        addAnimator(animators, mIconView, R.attr.guidedStepImeAppearingAnimation);
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public void onActivityExit(@NonNull List<Animator> animators) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentEnter(@NonNull List<Animator> animators) {
-        addAnimator(animators, mTitleView, R.attr.guidedStepEntryAnimation);
-        addAnimator(animators, mBreadcrumbView, R.attr.guidedStepEntryAnimation);
-        addAnimator(animators, mDescriptionView, R.attr.guidedStepEntryAnimation);
-        addAnimator(animators, mIconView, R.attr.guidedStepEntryAnimation);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentExit(@NonNull List<Animator> animators) {
-        addAnimator(animators, mTitleView, R.attr.guidedStepExitAnimation);
-        addAnimator(animators, mBreadcrumbView, R.attr.guidedStepExitAnimation);
-        addAnimator(animators, mDescriptionView, R.attr.guidedStepExitAnimation);
-        addAnimator(animators, mIconView, R.attr.guidedStepExitAnimation);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentReenter(@NonNull List<Animator> animators) {
-        addAnimator(animators, mTitleView, R.attr.guidedStepReentryAnimation);
-        addAnimator(animators, mBreadcrumbView, R.attr.guidedStepReentryAnimation);
-        addAnimator(animators, mDescriptionView, R.attr.guidedStepReentryAnimation);
-        addAnimator(animators, mIconView, R.attr.guidedStepReentryAnimation);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentReturn(@NonNull List<Animator> animators) {
-        addAnimator(animators, mTitleView, R.attr.guidedStepReturnAnimation);
-        addAnimator(animators, mBreadcrumbView, R.attr.guidedStepReturnAnimation);
-        addAnimator(animators, mDescriptionView, R.attr.guidedStepReturnAnimation);
-        addAnimator(animators, mIconView, R.attr.guidedStepReturnAnimation);
+    public void onImeDisappearing(@NonNull List<Animator> animators) {
+        addAnimator(animators, mTitleView, R.attr.guidedStepImeDisappearingAnimation);
+        addAnimator(animators, mBreadcrumbView, R.attr.guidedStepImeDisappearingAnimation);
+        addAnimator(animators, mDescriptionView, R.attr.guidedStepImeDisappearingAnimation);
+        addAnimator(animators, mIconView, R.attr.guidedStepImeDisappearingAnimation);
     }
 
     private void addAnimator(List<Animator> animators, View v, int attrId) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
index e4db2eb..21986d5 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
@@ -13,9 +13,12 @@
  */
 package android.support.v17.leanback.widget;
 
+import android.support.v17.leanback.R;
+
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.text.InputType;
 import android.util.Log;
 
 /**
@@ -34,47 +37,189 @@
 
     private static final String TAG = "GuidedAction";
 
-    public static final int NO_DRAWABLE = 0;
+    /**
+     * Special check set Id that is neither checkbox nor radio.
+     */
     public static final int NO_CHECK_SET = 0;
+    /**
+     * Default checkset Id for radio.
+     */
     public static final int DEFAULT_CHECK_SET_ID = 1;
+    /**
+     * Checkset Id for checkbox.
+     */
+    public static final int CHECKBOX_CHECK_SET_ID = -1;
 
     /**
-     * Builds a {@link GuidedAction} object.
+     * When finishing editing, goes to next action.
+     */
+    public static final long ACTION_ID_NEXT = -2;
+    /**
+     * When finishing editing, stay on current action.
+     */
+    public static final long ACTION_ID_CURRENT = -3;
+
+    /**
+     * Id of standard OK action.
+     */
+    public static final long ACTION_ID_OK = -4;
+
+    /**
+     * Id of standard Cancel action.
+     */
+    public static final long ACTION_ID_CANCEL = -5;
+
+    /**
+     * Id of standard Finish action.
+     */
+    public static final long ACTION_ID_FINISH = -6;
+
+    /**
+     * Id of standard Finish action.
+     */
+    public static final long ACTION_ID_CONTINUE = -7;
+
+    /**
+     * Id of standard Yes action.
+     */
+    public static final long ACTION_ID_YES = -8;
+
+    /**
+     * Id of standard No action.
+     */
+    public static final long ACTION_ID_NO = -9;
+
+    /**
+     * Builds a {@link GuidedAction} object.  When subclass GuidedAction, you may override this
+     * Builder class and call {@link #applyValues(GuidedAction)}.
      */
     public static class Builder {
         private long mId;
-        private String mTitle;
-        private String mDescription;
+        private CharSequence mTitle;
+        private CharSequence mEditTitle;
+        private CharSequence mDescription;
+        private CharSequence mEditDescription;
         private Drawable mIcon;
         private boolean mChecked;
         private boolean mMultilineDescription;
         private boolean mHasNext;
         private boolean mInfoOnly;
+        private boolean mEditable = false;
+        private boolean mDescriptionEditable = false;
+        private int mInputType = InputType.TYPE_CLASS_TEXT;
+        private int mDescriptionInputType = InputType.TYPE_CLASS_TEXT;
+        private int mEditInputType = InputType.TYPE_CLASS_TEXT;
+        private int mDescriptionEditInputType = InputType.TYPE_CLASS_TEXT;
         private int mCheckSetId = NO_CHECK_SET;
         private boolean mEnabled = true;
+        private boolean mFocusable = true;
         private Intent mIntent;
 
         /**
          * Builds the GuidedAction corresponding to this Builder.
          * @return the GuidedAction as configured through this Builder.
          */
-        public GuidedAction build() {
+        public final GuidedAction build() {
             GuidedAction action = new GuidedAction();
+            applyValues(action);
+            return action;
+        }
+
+        /**
+         * Subclass Builder may call this function to apply values.
+         * @param action GuidedAction to apply Builder values.
+         */
+        protected final void applyValues(GuidedAction action) {
             // Base Action values
             action.setId(mId);
             action.setLabel1(mTitle);
+            action.setEditTitle(mEditTitle);
             action.setLabel2(mDescription);
+            action.setEditDescription(mEditDescription);
             action.setIcon(mIcon);
 
             // Subclass values
             action.mIntent = mIntent;
+            action.mEditable = mEditable;
+            action.mDescriptionEditable = mDescriptionEditable;
+            action.mInputType = mInputType;
+            action.mDescriptionInputType = mDescriptionInputType;
+            action.mEditInputType = mEditInputType;
+            action.mDescriptionEditInputType = mDescriptionEditInputType;
             action.mChecked = mChecked;
             action.mCheckSetId = mCheckSetId;
             action.mMultilineDescription = mMultilineDescription;
             action.mHasNext = mHasNext;
             action.mInfoOnly = mInfoOnly;
             action.mEnabled = mEnabled;
-            return action;
+            action.mFocusable = mFocusable;
+        }
+
+        /**
+         * Construct a standard "OK" action with {@link GuidedAction#ACTION_ID_OK}.
+         * @param context Context for loading action title.
+         * @return The same Builder object.
+         */
+        public Builder constructOK(Context context) {
+            mId = ACTION_ID_OK;
+            mTitle = context.getString(android.R.string.ok);
+            return this;
+        }
+
+        /**
+         * Construct a standard "Cancel" action with {@link GuidedAction#ACTION_ID_CANCEL}.
+         * @param context Context for loading action title.
+         * @return The same Builder object.
+         */
+        public Builder constructCancel(Context context) {
+            mId = ACTION_ID_CANCEL;
+            mTitle = context.getString(android.R.string.cancel);
+            return this;
+        }
+
+        /**
+         * Construct a standard "Finish" action with {@link GuidedAction#ACTION_ID_FINISH}.
+         * @param context Context for loading action title.
+         * @return The same Builder object.
+         */
+        public Builder constructFinish(Context context) {
+            mId = ACTION_ID_FINISH;
+            mTitle = context.getString(R.string.lb_guidedaction_finish_title);
+            return this;
+        }
+
+        /**
+         * Construct a standard "Continue" action with {@link GuidedAction#ACTION_ID_CONTINUE}.
+         * @param context Context for loading action title.
+         * @return The same Builder object.
+         */
+        public Builder constructContinue(Context context) {
+            mId = ACTION_ID_CONTINUE;
+            mHasNext = true;
+            mTitle = context.getString(R.string.lb_guidedaction_continue_title);
+            return this;
+        }
+
+        /**
+         * Construct a standard "Yes" action with {@link GuidedAction#ACTION_ID_YES}.
+         * @param context Context for loading action title.
+         * @return The same Builder object.
+         */
+        public Builder constructYes(Context context) {
+            mId = ACTION_ID_YES;
+            mTitle = context.getString(android.R.string.yes);
+            return this;
+        }
+
+        /**
+         * Construct a standard "No" action with {@link GuidedAction#ACTION_ID_NO}.
+         * @param context Context for loading action title.
+         * @return The same Builder object.
+         */
+        public Builder constructNo(Context context) {
+            mId = ACTION_ID_NO;
+            mTitle = context.getString(android.R.string.no);
+            return this;
         }
 
         /**
@@ -92,22 +237,41 @@
          * action to be taken on click, e.g. "Continue" or "Cancel".
          * @param title The title for this action.
          */
-        public Builder title(String title) {
+        public Builder title(CharSequence title) {
             mTitle = title;
             return this;
         }
 
         /**
+         * Sets the optional title text to edit.  When TextView is activated, the edit title
+         * replaces the string of title.
+         */
+        public Builder editTitle(CharSequence editTitle) {
+            mEditTitle = editTitle;
+            return this;
+        }
+
+        /**
          * Sets the description for this action.  The description is typically a longer string
          * providing extra information on what the action will do.
          * @param description The description for this action.
          */
-        public Builder description(String description) {
+        public Builder description(CharSequence description) {
             mDescription = description;
             return this;
         }
 
         /**
+         * Sets the optional description text to edit.  When TextView is activated, the edit
+         * description replaces the string of description.
+         * @param description The description to edit for this action.
+         */
+        public Builder editDescription(CharSequence description) {
+            mEditDescription = description;
+            return this;
+        }
+
+        /**
          * Sets the intent associated with this action.  Clients would typically fire this intent
          * directly when the action is clicked.
          * @param intent The intent associated with this action.
@@ -138,22 +302,96 @@
         }
 
         /**
+         * Indicates whether this action title is editable. Note: Editable actions cannot also be
+         * checked, or belong to a check set.
+         * @param editable Whether this action is editable.
+         */
+        public Builder editable(boolean editable) {
+            mEditable = editable;
+            if (mChecked || mCheckSetId != NO_CHECK_SET) {
+                throw new IllegalArgumentException("Editable actions cannot also be checked");
+            }
+            return this;
+        }
+
+        /**
+         * Indicates whether this action's description is editable
+         * @param editable Whether this action description is editable.
+         */
+        public Builder descriptionEditable(boolean editable) {
+            mDescriptionEditable = editable;
+            if (mChecked || mCheckSetId != NO_CHECK_SET) {
+                throw new IllegalArgumentException("Editable actions cannot also be checked");
+            }
+            return this;
+        }
+
+        /**
+         * Sets {@link InputType} of this action title not in editing.
+         *
+         * @param inputType InputType for the action title not in editing.
+         */
+        public Builder inputType(int inputType) {
+            mInputType = inputType;
+            return this;
+        }
+
+        /**
+         * Sets {@link InputType} of this action description not in editing.
+         *
+         * @param inputType InputType for the action description not in editing.
+         */
+        public Builder descriptionInputType(int inputType) {
+            mDescriptionInputType = inputType;
+            return this;
+        }
+
+
+        /**
+         * Sets {@link InputType} of this action title in editing.
+         *
+         * @param inputType InputType for the action title in editing.
+         */
+        public Builder editInputType(int inputType) {
+            mEditInputType = inputType;
+            return this;
+        }
+
+        /**
+         * Sets {@link InputType} of this action description in editing.
+         *
+         * @param inputType InputType for the action description in editing.
+         */
+        public Builder descriptionEditInputType(int inputType) {
+            mDescriptionEditInputType = inputType;
+            return this;
+        }
+
+
+        /**
          * Indicates whether this action is initially checked.
          * @param checked Whether this action is checked.
          */
         public Builder checked(boolean checked) {
             mChecked = checked;
+            if (mEditable || mDescriptionEditable) {
+                throw new IllegalArgumentException("Editable actions cannot also be checked");
+            }
             return this;
         }
 
         /**
-         * Indicates whether this action is part of a single-select group similar to radio buttons.
-         * When one item in a check set is checked, all others with the same check set ID will be
-         * unchecked automatically.
-         * @param checkSetId The check set ID, or {@link #NO_CHECK_SET) to indicate no check set.
+         * Indicates whether this action is part of a single-select group similar to radio buttons
+         * or this action is a checkbox. When one item in a check set is checked, all others with
+         * the same check set ID will be nchecked automatically.
+         * @param checkSetId The check set ID, or {@link GuidedAction#NO_CHECK_SET} to indicate not
+         * radio or checkbox, or {@link GuidedAction#CHECKBOX_CHECK_SET_ID} to indicate a checkbox.
          */
         public Builder checkSetId(int checkSetId) {
             mCheckSetId = checkSetId;
+            if (mEditable || mDescriptionEditable) {
+                throw new IllegalArgumentException("Editable actions cannot also be in check sets");
+            }
             return this;
         }
 
@@ -193,18 +431,37 @@
             mEnabled = enabled;
             return this;
         }
+
+        /**
+         * Indicates whether this action can take focus.
+         * @param focusable
+         * @return The same Builder object.
+         */
+        public Builder focusable(boolean focusable) {
+            mFocusable = focusable;
+            return this;
+        }
     }
 
-    private boolean mChecked;
+    private CharSequence mEditTitle;
+    private CharSequence mEditDescription;
+    private boolean mEditable;
+    private boolean mDescriptionEditable;
+    private int mInputType;
+    private int mDescriptionInputType;
+    private int mEditInputType;
+    private int mDescriptionEditInputType;
     private boolean mMultilineDescription;
     private boolean mHasNext;
+    private boolean mChecked;
     private boolean mInfoOnly;
     private int mCheckSetId;
     private boolean mEnabled;
+    private boolean mFocusable;
 
     private Intent mIntent;
 
-    private GuidedAction() {
+    protected GuidedAction() {
         super(0);
     }
 
@@ -217,14 +474,74 @@
     }
 
     /**
+     * Sets the title of this action.
+     * @param title The title set when this action was built.
+     */
+    public void setTitle(CharSequence title) {
+        setLabel1(title);
+    }
+
+    /**
+     * Returns the optional title text to edit.  When not null, it is being edited instead of
+     * {@link #getTitle()}.
+     * @return Optional title text to edit instead of {@link #getTitle()}.
+     */
+    public CharSequence getEditTitle() {
+        return mEditTitle;
+    }
+
+    /**
+     * Sets the optional title text to edit instead of {@link #setTitle(CharSequence)}.
+     * @param editTitle Optional title text to edit instead of {@link #setTitle(CharSequence)}.
+     */
+    public void setEditTitle(CharSequence editTitle) {
+        mEditTitle = editTitle;
+    }
+
+    /**
+     * Returns the optional description text to edit.  When not null, it is being edited instead of
+     * {@link #getDescription()}.
+     * @return Optional description text to edit instead of {@link #getDescription()}.
+     */
+    public CharSequence getEditDescription() {
+        return mEditDescription;
+    }
+
+    /**
+     * Sets the optional description text to edit instead of {@link #setDescription(CharSequence)}.
+     * @param editDescription Optional description text to edit instead of
+     * {@link #setDescription(CharSequence)}.
+     */
+    public void setEditDescription(CharSequence editDescription) {
+        mEditDescription = editDescription;
+    }
+
+    /**
+     * Returns true if {@link #getEditTitle()} is not null.  When true, the {@link #getEditTitle()}
+     * is being edited instead of {@link #getTitle()}.
+     * @return true if {@link #getEditTitle()} is not null.
+     */
+    public boolean isEditTitleUsed() {
+        return mEditTitle != null;
+    }
+
+    /**
      * Returns the description of this action.
-     * @return The description set when this action was built.
+     * @return The description of this action.
      */
     public CharSequence getDescription() {
         return getLabel2();
     }
 
     /**
+     * Sets the description of this action.
+     * @param description The description of the action.
+     */
+    public void setDescription(CharSequence description) {
+        setLabel2(description);
+    }
+
+    /**
      * Returns the intent associated with this action.
      * @return The intent set when this action was built.
      */
@@ -233,6 +550,55 @@
     }
 
     /**
+     * Returns whether this action title is editable.
+     * @return true if the action title is editable, false otherwise.
+     */
+    public boolean isEditable() {
+        return mEditable;
+    }
+
+    /**
+     * Returns whether this action description is editable.
+     * @return true if the action description is editable, false otherwise.
+     */
+    public boolean isDescriptionEditable() {
+        return mDescriptionEditable;
+    }
+
+    /**
+     * Returns InputType of action title in editing; only valid when {@link #isEditable()} is true.
+     * @return InputType of action title in editing.
+     */
+    public int getEditInputType() {
+        return mEditInputType;
+    }
+
+    /**
+     * Returns InputType of action description in editing; only valid when
+     * {@link #isDescriptionEditable()} is true.
+     * @return InputType of action description in editing.
+     */
+    public int getDescriptionEditInputType() {
+        return mDescriptionEditInputType;
+    }
+
+    /**
+     * Returns InputType of action title not in editing.
+     * @return InputType of action title not in editing.
+     */
+    public int getInputType() {
+        return mInputType;
+    }
+
+    /**
+     * Returns InputType of action description not in editing.
+     * @return InputType of action description not in editing.
+     */
+    public int getDescriptionInputType() {
+        return mDescriptionInputType;
+    }
+
+    /**
      * Returns whether this action is checked.
      * @return true if the action is currently checked, false otherwise.
      */
@@ -249,13 +615,13 @@
     }
 
     /**
-     * Returns the check set id this action is a part of. All actions in the
-     * same list with the same check set id are considered linked. When one
-     * of the actions within that set is selected, that action becomes
-     * checked, while all the other actions become unchecked.
+     * Returns the check set id this action is a part of. All actions in the same list with the same
+     * check set id are considered linked. When one of the actions within that set is selected, that
+     * action becomes checked, while all the other actions become unchecked.
      *
      * @return an integer representing the check set this action is a part of, or
-     *         {@link #NO_CHECK_SET} if this action isn't a part of a check set.
+     *         {@link #CHECKBOX_CHECK_SET_ID} if this is a checkbox, or {@link #NO_CHECK_SET} if
+     *         this action is not a checkbox or radiobutton.
      */
     public int getCheckSetId() {
         return mCheckSetId;
@@ -287,6 +653,22 @@
     }
 
     /**
+     * Returns whether this action is focusable.
+     * @return true if the action is currently focusable, false otherwise.
+     */
+    public boolean isFocusable() {
+        return mFocusable;
+    }
+
+    /**
+     * Sets whether this action is focusable.
+     * @param focusable Whether this action should be focusable.
+     */
+    public void setFocusable(boolean focusable) {
+        mFocusable = focusable;
+    }
+
+    /**
      * Returns whether this action will request further user input when selected, such as showing
      * another GuidedStepFragment or launching a new activity. Configured during construction.
      * @return true if the action will request further user input when selected, false otherwise.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java
new file mode 100644
index 0000000..8e052fb
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java
@@ -0,0 +1,58 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener;
+import android.util.AttributeSet;
+import android.widget.EditText;
+import android.view.KeyEvent;
+
+/**
+ * A custom EditText that satisfies the IME key monitoring requirements of GuidedStepFragment.
+ */
+public class GuidedActionEditText extends EditText implements ImeKeyMonitor {
+
+    private ImeKeyListener mKeyListener;
+
+    public GuidedActionEditText(Context ctx) {
+        this(ctx, null);
+    }
+
+    public GuidedActionEditText(Context ctx, AttributeSet attrs) {
+        this(ctx, attrs, android.R.attr.editTextStyle);
+    }
+
+    public GuidedActionEditText(Context ctx, AttributeSet attrs, int defStyleAttr) {
+        super(ctx, attrs, defStyleAttr);
+    }
+
+    @Override
+    public void setImeKeyListener(ImeKeyListener listener) {
+        mKeyListener = listener;
+    }
+
+    @Override
+    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+        boolean result = false;
+        if (mKeyListener != null) {
+            result = mKeyListener.onKeyPreIme(this, keyCode, event);
+        }
+        if (!result) {
+            result = super.onKeyPreIme(keyCode, event);
+        }
+        return result;
+    }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
index 15943b4..6e5d506 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
@@ -22,17 +22,21 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.support.annotation.NonNull;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.animation.DecelerateInterpolator;
+import android.view.inputmethod.EditorInfo;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -40,6 +44,8 @@
 import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
+import android.widget.Checkable;
+import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -81,11 +87,15 @@
  * </ul><p>
  * These view IDs are allowed to be missing, in which case the corresponding views in {@link
  * GuidedActionsStylist.ViewHolder} will be null.
+ * <p>
+ * In order to support editable actions, the view associated with guidedactions_item_title should
+ * be a subclass of {@link android.widget.EditText}, and should satisfy the {@link
+ * ImeKeyMonitor} interface.
  *
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsEntryAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorShowAnimation
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorHideAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsContainerStyle
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorStyle
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsListStyle
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContainerStyle
@@ -95,24 +105,30 @@
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemTitleStyle
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemDescriptionStyle
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemChevronStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionCheckedAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUncheckedAnimation
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionPressedAnimation
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUnpressedAnimation
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionEnabledChevronAlpha
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDisabledChevronAlpha
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidth
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthNoIcon
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMinLines
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMaxLines
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDescriptionMinLines
  * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionVerticalPadding
+ * @see android.R.styleable#Theme_listChoiceIndicatorSingle
+ * @see android.R.styleable#Theme_listChoiceIndicatorMultiple
  * @see android.support.v17.leanback.app.GuidedStepFragment
  * @see GuidedAction
  */
 public class GuidedActionsStylist implements FragmentAnimationProvider {
 
     /**
+     * Default viewType that associated with default layout Id for the action item.
+     * @see #getItemViewType(GuidedAction)
+     * @see #onProvideItemLayoutId(int)
+     * @see #onCreateViewHolder(ViewGroup, int)
+     */
+    public static final int VIEW_TYPE_DEFAULT = 0;
+
+    /**
      * ViewHolder caches information about the action item layouts' subviews. Subclasses of {@link
      * GuidedActionsStylist} may also wish to subclass this in order to add fields.
      * @see GuidedAction
@@ -127,6 +143,8 @@
         private ImageView mIconView;
         private ImageView mCheckmarkView;
         private ImageView mChevronView;
+        private boolean mInEditing;
+        private boolean mInEditingDescription;
 
         /**
          * Constructs an ViewHolder and caches the relevant subviews.
@@ -158,6 +176,14 @@
         }
 
         /**
+         * Convenience method to return an editable version of the title, if possible,
+         * or null if the title view isn't an EditText.
+         */
+        public EditText getEditableTitleView() {
+            return (mTitleView instanceof EditText) ? (EditText)mTitleView : null;
+        }
+
+        /**
          * Returns the description view within this view holder's view.
          */
         public TextView getDescriptionView() {
@@ -165,6 +191,14 @@
         }
 
         /**
+         * Convenience method to return an editable version of the description, if possible,
+         * or null if the description view isn't an EditText.
+         */
+        public EditText getEditableDescriptionView() {
+            return (mDescriptionView instanceof EditText) ? (EditText)mDescriptionView : null;
+        }
+
+        /**
          * Returns the icon view within this view holder's view.
          */
         public ImageView getIconView() {
@@ -185,19 +219,47 @@
             return mChevronView;
         }
 
+        /**
+         * Returns true if the TextView is in editing title or description, false otherwise.
+         */
+        public boolean isInEditing() {
+            return mInEditing;
+        }
+
+        /**
+         * Returns true if the TextView is in editing description, false otherwise.
+         */
+        public boolean isInEditingDescription() {
+            return mInEditingDescription;
+        }
+
+        public View getEditingView() {
+            if (mInEditing) {
+                return mInEditingDescription ?  mDescriptionView : mTitleView;
+            } else {
+                return null;
+            }
+        }
     }
 
     private static String TAG = "GuidedActionsStylist";
 
-    protected View mMainView;
-    protected VerticalGridView mActionsGridView;
-    protected View mSelectorView;
+    private ViewGroup mMainView;
+    private VerticalGridView mActionsGridView;
+    private View mBgView;
+    private View mSelectorView;
+    private View mContentView;
+    private boolean mButtonActions;
+
+    private Animator mSelectorAnimator;
 
     // Cached values from resources
+    private float mEnabledTextAlpha;
+    private float mDisabledTextAlpha;
+    private float mEnabledDescriptionAlpha;
+    private float mDisabledDescriptionAlpha;
     private float mEnabledChevronAlpha;
     private float mDisabledChevronAlpha;
-    private int mContentWidth;
-    private int mContentWidthNoIcon;
     private int mTitleMinLines;
     private int mTitleMaxLines;
     private int mDescriptionMinLines;
@@ -216,8 +278,17 @@
      * @return The view to be added to the caller's view hierarchy.
      */
     public View onCreateView(LayoutInflater inflater, ViewGroup container) {
-        mMainView = inflater.inflate(onProvideLayoutId(), container, false);
+        mMainView = (ViewGroup) inflater.inflate(onProvideLayoutId(), container, false);
+        mContentView = mMainView.findViewById(R.id.guidedactions_content);
         mSelectorView = mMainView.findViewById(R.id.guidedactions_selector);
+        mSelectorView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                updateSelectorView(false);
+            }
+        });
+        mBgView = mMainView.findViewById(R.id.guidedactions_list_background);
         if (mMainView instanceof VerticalGridView) {
             mActionsGridView = (VerticalGridView) mMainView;
         } else {
@@ -229,32 +300,23 @@
             mActionsGridView.setWindowAlignmentOffsetPercent(50f);
             mActionsGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
             if (mSelectorView != null) {
-                mActionsGridView.setOnScrollListener(new
-                        SelectorAnimator(mSelectorView, mActionsGridView));
+                mActionsGridView.setOnScrollListener(new RecyclerView.OnScrollListener() {
+                    @Override
+                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+                            if (mSelectorView.getAlpha() != 1f) {
+                                updateSelectorView(true);
+                            }
+                        }
+                    }
+                });
             }
         }
 
-        mActionsGridView.requestFocusFromTouch();
-
         if (mSelectorView != null) {
             // ALlow focus to move to other views
             mActionsGridView.getViewTreeObserver().addOnGlobalFocusChangeListener(
-                    new ViewTreeObserver.OnGlobalFocusChangeListener() {
-                        private boolean mChildFocused;
-
-                        @Override
-                        public void onGlobalFocusChanged(View oldFocus, View newFocus) {
-                            View focusedChild = mActionsGridView.getFocusedChild();
-                            if (focusedChild == null) {
-                                mSelectorView.setVisibility(View.INVISIBLE);
-                                mChildFocused = false;
-                            } else if (!mChildFocused) {
-                                mChildFocused = true;
-                                mSelectorView.setVisibility(View.VISIBLE);
-                                updateSelectorView(focusedChild);
-                            }
-                        }
-                    });
+                    mGlobalFocusChangeListener);
         }
 
         // Cache widths, chevron alpha values, max and min text lines, etc
@@ -262,8 +324,6 @@
         TypedValue val = new TypedValue();
         mEnabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionEnabledChevronAlpha);
         mDisabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionDisabledChevronAlpha);
-        mContentWidth = getDimension(ctx, val, R.attr.guidedActionContentWidth);
-        mContentWidthNoIcon = getDimension(ctx, val, R.attr.guidedActionContentWidthNoIcon);
         mTitleMinLines = getInteger(ctx, val, R.attr.guidedActionTitleMinLines);
         mTitleMaxLines = getInteger(ctx, val, R.attr.guidedActionTitleMaxLines);
         mDescriptionMinLines = getInteger(ctx, val, R.attr.guidedActionDescriptionMinLines);
@@ -271,10 +331,79 @@
         mDisplayHeight = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay().getHeight();
 
+        mEnabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_unselected_text_alpha));
+        mDisabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_disabled_text_alpha));
+        mEnabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_unselected_description_text_alpha));
+        mDisabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_disabled_description_text_alpha));
         return mMainView;
     }
 
     /**
+     * Default implementation turns on background for actions and applies different Ids to views so
+     * that GuidedStepFragment could run transitions against two action lists.  The method is called
+     * by GuidedStepFragment, app may override this function when replacing default layout file
+     * provided by {@link #onProvideLayoutId()}
+     */
+    public void setAsButtonActions() {
+        mButtonActions = true;
+        mMainView.setId(R.id.guidedactions_root2);
+        ViewCompat.setTransitionName(mMainView, "guidedactions_root2");
+        if (mActionsGridView != null) {
+            mActionsGridView.setId(R.id.guidedactions_list2);
+        }
+        if (mSelectorView != null) {
+            mSelectorView.setId(R.id.guidedactions_selector2);
+            ViewCompat.setTransitionName(mSelectorView, "guidedactions_selector2");
+        }
+        if (mContentView != null) {
+            mContentView.setId(R.id.guidedactions_content2);
+            ViewCompat.setTransitionName(mContentView, "guidedactions_content2");
+        }
+        if (mBgView != null) {
+            mBgView.setId(R.id.guidedactions_list_background2);
+            ViewCompat.setTransitionName(mBgView, "guidedactions_list_background2");
+            mBgView.setVisibility(View.VISIBLE);
+        }
+    }
+
+    /**
+     * Returns true if {@link #setAsButtonActions()} was called, false otherwise.
+     * @return True if {@link #setAsButtonActions()} was called, false otherwise.
+     */
+    public boolean isButtonActions() {
+        return mButtonActions;
+    }
+
+    final ViewTreeObserver.OnGlobalFocusChangeListener mGlobalFocusChangeListener =
+            new ViewTreeObserver.OnGlobalFocusChangeListener() {
+
+        @Override
+        public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+            updateSelectorView(false);
+        }
+    };
+
+    /**
+     * Called when destroy the View created by GuidedActionsStylist.
+     */
+    public void onDestroyView() {
+        if (mSelectorView != null) {
+            mActionsGridView.getViewTreeObserver().removeOnGlobalFocusChangeListener(
+                    mGlobalFocusChangeListener);
+        }
+        endSelectorAnimator();
+        mActionsGridView = null;
+        mSelectorView = null;
+        mContentView = null;
+        mBgView = null;
+        mMainView = null;
+    }
+
+    /**
      * Returns the VerticalGridView that displays the list of GuidedActions.
      * @return The VerticalGridView for this presenter.
      */
@@ -296,11 +425,25 @@
     }
 
     /**
+     * Return view type of action, each different type can have differently associated layout Id.
+     * Default implementation returns {@link #VIEW_TYPE_DEFAULT}.
+     * @param action  The action object.
+     * @return View type that used in {@link #onProvideItemLayoutId(int)}.
+     */
+    public int getItemViewType(GuidedAction action) {
+        return VIEW_TYPE_DEFAULT;
+    }
+
+    /**
      * Provides the resource ID of the layout defining the view for an individual guided actions.
      * Subclasses may override to provide their own customized layouts. The base implementation
      * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden,
      * the substituted layout should contain matching IDs for any views that should be managed by
-     * the base class; this can be achieved by starting with a copy of the base layout file.
+     * the base class; this can be achieved by starting with a copy of the base layout file. Note
+     * that in order for the item to support editing, the title view should both subclass {@link
+     * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link
+     * GuidedActionEditText}.  To support different types of Layouts, override {@link
+     * #onProvideItemLayoutId(int)}.
      * @return The resource ID of the layout to be inflated to define the view to display an
      * individual GuidedAction.
      */
@@ -309,8 +452,31 @@
     }
 
     /**
+     * Provides the resource ID of the layout defining the view for an individual guided actions.
+     * Subclasses may override to provide their own customized layouts. The base implementation
+     * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden,
+     * the substituted layout should contain matching IDs for any views that should be managed by
+     * the base class; this can be achieved by starting with a copy of the base layout file. Note
+     * that in order for the item to support editing, the title view should both subclass {@link
+     * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link
+     * GuidedActionEditText}.
+     * @param viewType View type returned by {@link #getItemViewType(GuidedAction)}
+     * @return The resource ID of the layout to be inflated to define the view to display an
+     * individual GuidedAction.
+     */
+    public int onProvideItemLayoutId(int viewType) {
+        if (viewType == VIEW_TYPE_DEFAULT) {
+            return onProvideItemLayoutId();
+        } else {
+            throw new RuntimeException("ViewType " + viewType +
+                    " not supported in GuidedActionsStylist");
+        }
+    }
+
+    /**
      * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
-     * may choose to return a subclass of ViewHolder.
+     * may choose to return a subclass of ViewHolder.  To support different view types, override
+     * {@link #onCreateViewHolder(ViewGroup, int)}
      * <p>
      * <i>Note: Should not actually add the created view to the parent; the caller will do
      * this.</i>
@@ -324,6 +490,25 @@
     }
 
     /**
+     * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
+     * may choose to return a subclass of ViewHolder.
+     * <p>
+     * <i>Note: Should not actually add the created view to the parent; the caller will do
+     * this.</i>
+     * @param parent The view group to be used as the parent of the new view.
+     * @param viewType The viewType returned by {@link #getItemViewType(GuidedAction)}
+     * @return The view to be added to the caller's view hierarchy.
+     */
+    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (viewType == VIEW_TYPE_DEFAULT) {
+            return onCreateViewHolder(parent);
+        }
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+        View v = inflater.inflate(onProvideItemLayoutId(viewType), parent, false);
+        return new ViewHolder(v);
+    }
+
+    /**
      * Binds a {@link ViewHolder} to a particular {@link GuidedAction}.
      * @param vh The view holder to be associated with the given action.
      * @param action The guided action to be displayed by the view holder's view.
@@ -333,31 +518,24 @@
 
         if (vh.mTitleView != null) {
             vh.mTitleView.setText(action.getTitle());
+            vh.mTitleView.setAlpha(action.isEnabled() ? mEnabledTextAlpha : mDisabledTextAlpha);
+            vh.mTitleView.setFocusable(action.isEditable());
         }
         if (vh.mDescriptionView != null) {
             vh.mDescriptionView.setText(action.getDescription());
             vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ?
                     View.GONE : View.VISIBLE);
+            vh.mDescriptionView.setAlpha(action.isEnabled() ? mEnabledDescriptionAlpha :
+                mDisabledDescriptionAlpha);
+            vh.mDescriptionView.setFocusable(action.isDescriptionEditable());
         }
         // Clients might want the check mark view to be gone entirely, in which case, ignore it.
-        if (vh.mCheckmarkView != null && vh.mCheckmarkView.getVisibility() != View.GONE) {
-            vh.mCheckmarkView.setVisibility(action.isChecked() ? View.VISIBLE : View.INVISIBLE);
-        }
-
-        if (vh.mContentView != null) {
-            ViewGroup.LayoutParams contentLp = vh.mContentView.getLayoutParams();
-            if (setIcon(vh.mIconView, action)) {
-                contentLp.width = mContentWidth;
-            } else {
-                contentLp.width = mContentWidthNoIcon;
-            }
-            vh.mContentView.setLayoutParams(contentLp);
+        if (vh.mCheckmarkView != null) {
+            onBindCheckMarkView(vh, action);
         }
 
         if (vh.mChevronView != null) {
-            vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.INVISIBLE);
-            vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
-                    mDisabledChevronAlpha);
+            onBindChevronView(vh, action);
         }
 
         if (action.hasMultilineDescription()) {
@@ -376,6 +554,89 @@
                 vh.mDescriptionView.setMaxLines(mDescriptionMinLines);
             }
         }
+        setEditingMode(vh, action, false);
+        if (action.isFocusable()) {
+            vh.view.setFocusable(true);
+            if (vh.view instanceof ViewGroup) {
+                ((ViewGroup) vh.view).setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+            }
+        } else {
+            vh.view.setFocusable(false);
+            if (vh.view instanceof ViewGroup) {
+                ((ViewGroup) vh.view).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+            }
+        }
+        setupImeOptions(vh, action);
+    }
+
+    /**
+     * Called by {@link #onBindViewHolder(ViewHolder, GuidedAction)} to setup IME options.  Default
+     * implementation assigns {@link EditorInfo#IME_ACTION_DONE}.  Subclass may override.
+     * @param vh The view holder to be associated with the given action.
+     * @param action The guided action to be displayed by the view holder's view.
+     */
+    protected void setupImeOptions(ViewHolder vh, GuidedAction action) {
+        setupNextImeOptions(vh.getEditableTitleView());
+        setupNextImeOptions(vh.getEditableDescriptionView());
+    }
+
+    private void setupNextImeOptions(EditText edit) {
+        if (edit != null) {
+            edit.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        }
+    }
+
+    public void setEditingMode(ViewHolder vh, GuidedAction action, boolean editing) {
+        if (editing != vh.mInEditing) {
+            vh.mInEditing = editing;
+            onEditingModeChange(vh, action, editing);
+        }
+    }
+
+    protected void onEditingModeChange(ViewHolder vh, GuidedAction action, boolean editing) {
+        TextView titleView = vh.getTitleView();
+        TextView descriptionView = vh.getDescriptionView();
+        if (editing) {
+            CharSequence editTitle = action.getEditTitle();
+            if (titleView != null && editTitle != null) {
+                titleView.setText(editTitle);
+            }
+            CharSequence editDescription = action.getEditDescription();
+            if (descriptionView != null && editDescription != null) {
+                descriptionView.setText(editDescription);
+            }
+            if (action.isDescriptionEditable()) {
+                if (descriptionView != null) {
+                    descriptionView.setVisibility(View.VISIBLE);
+                    descriptionView.setInputType(action.getDescriptionEditInputType());
+                }
+                vh.mInEditingDescription = true;
+            } else {
+                vh.mInEditingDescription = false;
+                if (titleView != null) {
+                    titleView.setInputType(action.getEditInputType());
+                }
+            }
+        } else {
+            if (titleView != null) {
+                titleView.setText(action.getTitle());
+            }
+            if (descriptionView != null) {
+                descriptionView.setText(action.getDescription());
+            }
+            if (vh.mInEditingDescription) {
+                if (descriptionView != null) {
+                    descriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ?
+                            View.GONE : View.VISIBLE);
+                    descriptionView.setInputType(action.getDescriptionInputType());
+                }
+                vh.mInEditingDescription = false;
+            } else {
+                if (titleView != null) {
+                    titleView.setInputType(action.getInputType());
+                }
+            }
+        }
     }
 
     /**
@@ -402,31 +663,77 @@
     }
 
     /**
-     * Animates the view holder's view (or subviews thereof) when the action has had its check
-     * state changed.
+     * Resets the view holder's view to unpressed state.
+     * @param vh The view holder associated with the relevant action.
+     */
+    public void onAnimateItemPressedCancelled(ViewHolder vh) {
+        createAnimator(vh.view, R.attr.guidedActionUnpressedAnimation).end();
+    }
+
+    /**
+     * Animates the view holder's view (or subviews thereof) when the action has had its check state
+     * changed. Default implementation calls setChecked() if {@link ViewHolder#getCheckmarkView()}
+     * is instance of {@link Checkable}.
+     *
      * @param vh The view holder associated with the relevant action.
      * @param checked True if the action has become checked, false if it has become unchecked.
+     * @see #onBindCheckMarkView(ViewHolder, GuidedAction)
      */
     public void onAnimateItemChecked(ViewHolder vh, boolean checked) {
-        final View checkView = vh.mCheckmarkView;
-        if (checkView != null) {
-            if (checked) {
-                checkView.setVisibility(View.VISIBLE);
-                createAnimator(checkView, R.attr.guidedActionCheckedAnimation).start();
-            } else {
-                Animator animator = createAnimator(checkView,
-                        R.attr.guidedActionUncheckedAnimation);
-                animator.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        checkView.setVisibility(View.INVISIBLE);
-                    }
-                });
-                animator.start();
-            }
+        if (vh.mCheckmarkView instanceof Checkable) {
+            ((Checkable) vh.mCheckmarkView).setChecked(checked);
         }
     }
 
+    /**
+     * Sets states of check mark view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}
+     * when action's checkset Id is other than {@link GuidedAction#NO_CHECK_SET}. Default
+     * implementation assigns drawable loaded from theme attribute
+     * {@link android.R.attr#listChoiceIndicatorMultiple} for checkbox or
+     * {@link android.R.attr#listChoiceIndicatorSingle} for radio button. Subclass rarely needs
+     * override the method, instead app can provide its own drawable that supports transition
+     * animations, change theme attributes {@link android.R.attr#listChoiceIndicatorMultiple} and
+     * {@link android.R.attr#listChoiceIndicatorSingle} in {android.support.v17.leanback.R.
+     * styleable#LeanbackGuidedStepTheme}.
+     *
+     * @param vh The view holder associated with the relevant action.
+     * @param action The GuidedAction object to bind to.
+     * @see #onAnimateItemChecked(ViewHolder, boolean)
+     */
+    public void onBindCheckMarkView(ViewHolder vh, GuidedAction action) {
+        if (action.getCheckSetId() != GuidedAction.NO_CHECK_SET) {
+            vh.mCheckmarkView.setVisibility(View.VISIBLE);
+            int attrId = action.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID ?
+                    android.R.attr.listChoiceIndicatorMultiple :
+                    android.R.attr.listChoiceIndicatorSingle;
+            final Context context = vh.mCheckmarkView.getContext();
+            Drawable drawable = null;
+            TypedValue typedValue = new TypedValue();
+            if (context.getTheme().resolveAttribute(attrId, typedValue, true)) {
+                drawable = ContextCompat.getDrawable(context, typedValue.resourceId);
+            }
+            vh.mCheckmarkView.setImageDrawable(drawable);
+            if (vh.mCheckmarkView instanceof Checkable) {
+                ((Checkable) vh.mCheckmarkView).setChecked(action.isChecked());
+            }
+        } else {
+            vh.mCheckmarkView.setVisibility(View.GONE);
+        }
+    }
+
+    /**
+     * Sets states of chevron view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}.
+     * Subclass may override.
+     *
+     * @param vh The view holder associated with the relevant action.
+     * @param action The GuidedAction object to bind to.
+     */
+    public void onBindChevronView(ViewHolder vh, GuidedAction action) {
+        vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.GONE);
+        vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
+                mDisabledChevronAlpha);
+    }
+
     /*
      * ==========================================
      * FragmentAnimationProvider overrides
@@ -437,50 +744,16 @@
      * {@inheritDoc}
      */
     @Override
-    public void onActivityEnter(@NonNull List<Animator> animators) {
-        animators.add(createAnimator(mMainView, R.attr.guidedActionsEntryAnimation));
+    public void onImeAppearing(@NonNull List<Animator> animators) {
+        animators.add(createAnimator(mContentView, R.attr.guidedStepImeAppearingAnimation));
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public void onActivityExit(@NonNull List<Animator> animators) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentEnter(@NonNull List<Animator> animators) {
-        animators.add(createAnimator(mActionsGridView, R.attr.guidedStepEntryAnimation));
-        animators.add(createAnimator(mSelectorView, R.attr.guidedStepEntryAnimation));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentExit(@NonNull List<Animator> animators) {
-        animators.add(createAnimator(mActionsGridView, R.attr.guidedStepExitAnimation));
-        animators.add(createAnimator(mSelectorView, R.attr.guidedStepExitAnimation));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentReenter(@NonNull List<Animator> animators) {
-        animators.add(createAnimator(mActionsGridView, R.attr.guidedStepReentryAnimation));
-        animators.add(createAnimator(mSelectorView, R.attr.guidedStepReentryAnimation));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFragmentReturn(@NonNull List<Animator> animators) {
-        animators.add(createAnimator(mActionsGridView, R.attr.guidedStepReturnAnimation));
-        animators.add(createAnimator(mSelectorView, R.attr.guidedStepReturnAnimation));
+    public void onImeDisappearing(@NonNull List<Animator> animators) {
+        animators.add(createAnimator(mContentView, R.attr.guidedStepImeDisappearingAnimation));
     }
 
     /*
@@ -489,15 +762,6 @@
      * ==========================================
      */
 
-    private void updateSelectorView(View focusedChild) {
-        // Display the selector view.
-        int height = focusedChild.getHeight();
-        LayoutParams lp = mSelectorView.getLayoutParams();
-        lp.height = height;
-        mSelectorView.setLayoutParams(lp);
-        mSelectorView.setAlpha(1f);
-    }
-
     private float getFloat(Context ctx, TypedValue typedValue, int attrId) {
         ctx.getTheme().resolveAttribute(attrId, typedValue, true);
         // Android resources don't have a native float type, so we have to use strings.
@@ -551,96 +815,43 @@
         return (int)(mDisplayHeight - 2*mVerticalPadding - 2*mTitleMaxLines*title.getLineHeight());
     }
 
-    /**
-     * SelectorAnimator
-     * Controls animation for selected item backgrounds
-     * TODO: Move into focus animation override?
-     */
-    private static class SelectorAnimator extends RecyclerView.OnScrollListener {
-
-        private final View mSelectorView;
-        private final ViewGroup mParentView;
-        private volatile boolean mFadedOut = true;
-
-        SelectorAnimator(View selectorView, ViewGroup parentView) {
-            mSelectorView = selectorView;
-            mParentView = parentView;
+    private void endSelectorAnimator() {
+        if (mSelectorAnimator != null) {
+            mSelectorAnimator.end();
+            mSelectorAnimator = null;
         }
+    }
 
-        // We want to fade in the selector if we've stopped scrolling on it. If
-        // we're scrolling, we want to ensure to dim the selector if we haven't
-        // already. We dim the last highlighted view so that while a user is
-        // scrolling, nothing is highlighted.
-        @Override
-        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-            Animator animator = null;
-            boolean fadingOut = false;
-            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
-                // The selector starts with a height of 0. In order to scale up from
-                // 0, we first need the set the height to 1 and scale from there.
-                View focusedChild = mParentView.getFocusedChild();
-                if (focusedChild != null) {
-                    int selectorHeight = mSelectorView.getHeight();
-                    float scaleY = (float) focusedChild.getHeight() / selectorHeight;
-                    AnimatorSet animators = (AnimatorSet)createAnimator(mSelectorView,
-                            R.attr.guidedActionsSelectorShowAnimation);
-                    if (mFadedOut) {
-                        // selector is completely faded out, so we can just scale before fading in.
-                        mSelectorView.setScaleY(scaleY);
-                        animator = animators.getChildAnimations().get(0);
-                    } else {
-                        // selector is not faded out, so we must animate the scale as we fade in.
-                        ((ObjectAnimator)animators.getChildAnimations().get(1))
-                                .setFloatValues(scaleY);
-                        animator = animators;
-                    }
-                }
+    private void updateSelectorView(boolean animate) {
+        if (mActionsGridView == null || mSelectorView == null || mSelectorView.getHeight() <= 0) {
+            return;
+        }
+        final View focusedChild = mActionsGridView.getFocusedChild();
+        endSelectorAnimator();
+        if (focusedChild == null || !mActionsGridView.hasFocus()
+                || mActionsGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
+            if (animate) {
+                mSelectorAnimator = createAnimator(mSelectorView,
+                        R.attr.guidedActionsSelectorHideAnimation);
+                mSelectorAnimator.start();
             } else {
-                animator = createAnimator(mSelectorView, R.attr.guidedActionsSelectorHideAnimation);
-                fadingOut = true;
+                mSelectorView.setAlpha(0f);
             }
-            if (animator != null) {
-                animator.addListener(new Listener(fadingOut));
-                animator.start();
-            }
-        }
-
-        /**
-         * Sets {@link BaseScrollAdapterFragment#mFadedOut}
-         * {@link BaseScrollAdapterFragment#mFadedOut} is true, iff
-         * {@link BaseScrollAdapterFragment#mSelectorView} has an alpha of 0
-         * (faded out). If false the view either has an alpha of 1 (visible) or
-         * is in the process of animating.
-         */
-        private class Listener implements Animator.AnimatorListener {
-            private boolean mFadingOut;
-            private boolean mCanceled;
-
-            public Listener(boolean fadingOut) {
-                mFadingOut = fadingOut;
-            }
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                if (!mFadingOut) {
-                    mFadedOut = false;
-                }
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!mCanceled && mFadingOut) {
-                    mFadedOut = true;
-                }
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mCanceled = true;
-            }
-
-            @Override
-            public void onAnimationRepeat(Animator animation) {
+        } else {
+            final float scaleY = (float) focusedChild.getHeight() / mSelectorView.getHeight();
+            Rect r = new Rect(0, 0, focusedChild.getWidth(), focusedChild.getHeight());
+            mMainView.offsetDescendantRectToMyCoords(focusedChild, r);
+            mMainView.offsetRectIntoDescendantCoords(mSelectorView, r);
+            mSelectorView.setTranslationY(r.exactCenterY() - mSelectorView.getHeight() * 0.5f);
+            if (animate) {
+                mSelectorAnimator = createAnimator(mSelectorView,
+                        R.attr.guidedActionsSelectorShowAnimation);
+                ((ObjectAnimator) ((AnimatorSet) mSelectorAnimator).getChildAnimations().get(1))
+                        .setFloatValues(scaleY);
+                mSelectorAnimator.start();
+            } else {
+                mSelectorView.setAlpha(1f);
+                mSelectorView.setScaleY(scaleY);
             }
         }
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
index 2c1c7e0..08eb617 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
@@ -18,60 +18,288 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.v17.leanback.R;
-import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 /**
- * A subclass of {@link BaseCardView} with an {@link ImageView} as its main region.
+ * A subclass of {@link BaseCardView} with an {@link ImageView} as its main
+ * region. The {@link ImageCardView} is highly customizable and can be used for
+ * various use-cases by adjusting the ImageViewCard's type to any combination of
+ * Title, Content, Badge or ImageOnly.
+ * <p>
+ * <h3>Styling</h3> There are three different ways to style the ImageCardView.
+ * <br>
+ * No matter what way you use, all your styles applied to an ImageCardView have
+ * to extend the style {@link R.style#Widget_Leanback_ImageCardViewStyle}.
+ * <p>
+ * <u>Example:</u><br>
+ * 
+ * <pre>
+ * {@code <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
+        <item name="cardBackground">#F0F</item>
+        <item name="lbImageCardViewType">Title|Content</item>
+        <item name="lbImageCardViewInfoAreaStyle">@style/ImageCardViewColoredInfoArea</item>
+        <item name="lbImageCardViewTitleStyle">@style/ImageCardViewColoredTitle</item>
+    </style>}
+ * </pre>
+ * <p>
+ * The first possibility is to set a custom Style in the Leanback Theme's
+ * attribute <code>imageCardViewStyle</code>. The style set here, is the default
+ * style for all ImageCardViews. The other two possibilities allow you to style
+ * a particular ImageCardView. This is usefull if you want to create multiple
+ * types of cards. E.g. you might want to display a card with only a title and
+ * another one with title and content. Thus you need to define two different
+ * <code>ImageCardViewStyles</code> and apply them to the ImageCardViews. You
+ * can do this by either using a the {@link #ImageCardView(Context, int)}
+ * constructor and passing a style as second argument or by setting the style in
+ * a layout.
+ * <p>
+ * <u>Example (using constructor):</u><br>
+ * 
+ * <pre>
+ * {@code
+ *     new ImageCardView(context, R.style.CustomImageCardViewStyle);
+ * }
+ * </pre>
+ * 
+ * <u>Example (using style attribute in a layout):</u><br>
+ * 
+ * <pre>
+ * {@code     <android.support.v17.leanback.widget.ImageCardView
+        android:id="@+id/imageCardView"
+        style="@style/CustomImageCardViewStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+    </android.support.v17.leanback.widget.ImageCardView>}
+ * </pre>
+ * <p>
+ * You can style all ImageCardView's components such as the title, content,
+ * badge, infoArea and the image itself by extending the corresponding style and
+ * overriding the specific attribute in your custom
+ * <code>ImageCardViewStyle</code>.
+ * 
+ * <h3>Components</h3> The ImageCardView contains three components which can be
+ * combined in any combination:
+ * <ul>
+ * <li>Title: The card's title</li>
+ * <li>Content: A short description</li>
+ * <li>Badge: An icon which can be displayed on the right or left side of the
+ * card.</li>
+ * </ul>
+ * In order to choose the components you want to use in your ImageCardView, you
+ * have to specify them in the <code>lbImageCardViewType</code> attribute of
+ * your custom <code>ImageCardViewStyle</code>. You can combine the following
+ * values: <code>Title, Content, IconOnRight, IconOnLeft, ImageOnly</code>.
+ * <p>
+ * <u>Examples:</u><br>
+ * 
+ * <pre>
+ * {@code <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
+        ...
+        <item name="lbImageCardViewType">Title|Content|IconOnLeft</item>
+        ...
+    </style>}
+ * </pre>
+ * 
+ * <pre>
+ * {@code <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
+        ...
+        <item name="lbImageCardViewType">ImageOnly</item>
+        ...
+    </style>}
+ * </pre>
+ * 
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackTheme_imageCardViewStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewType
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewTitleStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewContentStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewBadgeStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewImageStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewInfoAreaStyle
  */
 public class ImageCardView extends BaseCardView {
 
+    public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0;
+    public static final int CARD_TYPE_FLAG_TITLE = 1;
+    public static final int CARD_TYPE_FLAG_CONTENT = 2;
+    public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4;
+    public static final int CARD_TYPE_FLAG_ICON_LEFT = 8;
+
     private ImageView mImageView;
-    private View mInfoArea;
+    private ViewGroup mInfoArea;
     private TextView mTitleView;
     private TextView mContentView;
     private ImageView mBadgeImage;
     private boolean mAttachedToWindow;
 
+    /**
+     * Create an ImageCardView using a given style for customization.
+     * 
+     * @param context
+     *            The Context the view is running in, through which it can
+     *            access the current theme, resources, etc.
+     * @param styleResId
+     *            The resourceId of the style you want to apply to the
+     *            ImageCardView. The style has to extend
+     *            {@link R.style#Widget_Leanback_ImageCardViewStyle}.
+     */
+    public ImageCardView(Context context, int styleResId) {
+        super(new ContextThemeWrapper(context, styleResId), null, 0);
+        buildImageCardView(styleResId);
+    }
+
+    /**
+     * @see #View(Context, AttributeSet, int)
+     */
+    public ImageCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(getStyledContext(context, attrs, defStyleAttr), attrs, defStyleAttr);
+        buildImageCardView(getImageCardViewStyle(context, attrs, defStyleAttr));
+    }
+
+    private void buildImageCardView(int styleResId) {
+        // Make sure the ImageCardView is focusable.
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+
+        LayoutInflater inflater = LayoutInflater.from(getContext());
+        inflater.inflate(R.layout.lb_image_card_view, this);
+        TypedArray cardAttrs = getContext().obtainStyledAttributes(styleResId, R.styleable.lbImageCardView);
+        int cardType = cardAttrs.getInt(R.styleable.lbImageCardView_lbImageCardViewType, CARD_TYPE_FLAG_IMAGE_ONLY);
+        boolean hasImageOnly = cardType == CARD_TYPE_FLAG_IMAGE_ONLY;
+        boolean hasTitle = (cardType & CARD_TYPE_FLAG_TITLE) == CARD_TYPE_FLAG_TITLE;
+        boolean hasContent = (cardType & CARD_TYPE_FLAG_CONTENT) == CARD_TYPE_FLAG_CONTENT;
+        boolean hasIconRight = (cardType & CARD_TYPE_FLAG_ICON_RIGHT) == CARD_TYPE_FLAG_ICON_RIGHT;
+        boolean hasIconLeft = !hasIconRight && (cardType & CARD_TYPE_FLAG_ICON_LEFT) == CARD_TYPE_FLAG_ICON_LEFT;
+
+        mImageView = (ImageView) findViewById(R.id.main_image);
+        if (mImageView.getDrawable() == null) {
+            mImageView.setVisibility(View.INVISIBLE);
+        }
+
+        mInfoArea = (ViewGroup) findViewById(R.id.info_field);
+        if (hasImageOnly) {
+            removeView(mInfoArea);
+            cardAttrs.recycle();
+            return;
+        }
+        // Create children
+        if (hasTitle) {
+            mTitleView = (TextView) inflater.inflate(R.layout.lb_image_card_view_themed_title, mInfoArea, false);
+            mInfoArea.addView(mTitleView);
+        }
+
+        if (hasContent) {
+            mContentView = (TextView) inflater.inflate(R.layout.lb_image_card_view_themed_content, mInfoArea, false);
+            mInfoArea.addView(mContentView);
+        }
+
+        if (hasIconRight || hasIconLeft) {
+            int layoutId = R.layout.lb_image_card_view_themed_badge_right;
+            if (hasIconLeft) {
+                layoutId = R.layout.lb_image_card_view_themed_badge_left;
+            }
+            mBadgeImage = (ImageView) inflater.inflate(layoutId, mInfoArea, false);
+            mInfoArea.addView(mBadgeImage);
+        }
+
+        // Set up LayoutParams for children
+        if (hasTitle && !hasContent && mBadgeImage != null) {
+            RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) mTitleView
+                    .getLayoutParams();
+            // Adjust title TextView if there is an icon but no content
+            if (hasIconLeft) {
+                relativeLayoutParams.addRule(RelativeLayout.END_OF, mBadgeImage.getId());
+            } else {
+                relativeLayoutParams.addRule(RelativeLayout.START_OF, mBadgeImage.getId());
+            }
+            mTitleView.setLayoutParams(relativeLayoutParams);
+        }
+
+        // Set up LayoutParams for children
+        if (hasContent) {
+            RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) mContentView
+                    .getLayoutParams();
+            if (!hasTitle) {
+                relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+            }
+            // Adjust content TextView if icon is on the left
+            if (hasIconLeft) {
+                relativeLayoutParams.removeRule(RelativeLayout.START_OF);
+                relativeLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
+                relativeLayoutParams.addRule(RelativeLayout.END_OF, mBadgeImage.getId());
+            }
+            mContentView.setLayoutParams(relativeLayoutParams);
+        }
+
+        if (mBadgeImage != null) {
+            RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) mBadgeImage
+                    .getLayoutParams();
+            if (hasContent) {
+                relativeLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, mContentView.getId());
+            } else if (hasTitle) {
+                relativeLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, mTitleView.getId());
+            }
+            mBadgeImage.setLayoutParams(relativeLayoutParams);
+        }
+
+        // Backward compatibility: Newly created ImageCardViews should change
+        // the InfoArea's background color in XML using the corresponding style.
+        // However, since older implementations might make use of the
+        // 'infoAreaBackground' attribute, we have to make sure to support it.
+        // If the user has set a specific value here, it will differ from null.
+        // In this case, we do want to override the value set in the style.
+        Drawable background = cardAttrs.getDrawable(R.styleable.lbImageCardView_infoAreaBackground);
+        if (null != background) {
+            setInfoAreaBackground(background);
+        }
+        // Backward compatibility: There has to be an icon in the default
+        // version. If there is one, we have to set it's visibility to 'GONE'.
+        // Disabling 'adjustIconVisibility' allows the user to set the icon's
+        // visibility state in XML rather than code.
+        if (mBadgeImage != null && mBadgeImage.getDrawable() == null) {
+            mBadgeImage.setVisibility(View.GONE);
+        }
+        cardAttrs.recycle();
+    }
+
+    private static Context getStyledContext(Context context, AttributeSet attrs, int defStyleAttr) {
+        int style = getImageCardViewStyle(context, attrs, defStyleAttr);
+        return new ContextThemeWrapper(context, style);
+    }
+
+    private static int getImageCardViewStyle(Context context, AttributeSet attrs, int defStyleAttr) {
+        // Read style attribute defined in XML layout.
+        int style = null == attrs ? 0 : attrs.getStyleAttribute();
+        if (0 == style) {
+            // Not found? Read global ImageCardView style from Theme attribute.
+            TypedArray styledAttrs = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
+            style = styledAttrs.getResourceId(R.styleable.LeanbackTheme_imageCardViewStyle, 0);
+            styledAttrs.recycle();
+        }
+        return style;
+    }
+
+    /**
+     * @see #View(Context)
+     */
     public ImageCardView(Context context) {
         this(context, null);
     }
 
+    /**
+     * @see #View(Context, AttributeSet)
+     */
     public ImageCardView(Context context, AttributeSet attrs) {
         this(context, attrs, R.attr.imageCardViewStyle);
     }
 
-    public ImageCardView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        LayoutInflater inflater = LayoutInflater.from(context);
-        View v = inflater.inflate(R.layout.lb_image_card_view, this);
-
-        mImageView = (ImageView) v.findViewById(R.id.main_image);
-        mImageView.setVisibility(View.INVISIBLE);
-        mInfoArea = v.findViewById(R.id.info_field);
-        mTitleView = (TextView) v.findViewById(R.id.title_text);
-        mContentView = (TextView) v.findViewById(R.id.content_text);
-        mBadgeImage = (ImageView) v.findViewById(R.id.extra_badge);
-
-        if (mInfoArea != null) {
-            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbImageCardView,
-                    defStyle, 0);
-            try {
-                setInfoAreaBackground(
-                        a.getDrawable(R.styleable.lbImageCardView_infoAreaBackground));
-            } finally {
-                a.recycle();
-            }
-        }
-    }
-
     /**
      * Returns the main image view.
      */
@@ -170,7 +398,7 @@
 
     /**
      * Sets the info area background color.
-     */    
+     */
     public void setInfoAreaBackgroundColor(@ColorInt int color) {
         if (mInfoArea != null) {
             mInfoArea.setBackgroundColor(color);
@@ -184,7 +412,6 @@
         if (mTitleView == null) {
             return;
         }
-
         mTitleView.setText(text);
     }
 
@@ -206,7 +433,6 @@
         if (mContentView == null) {
             return;
         }
-
         mContentView.setText(text);
     }
 
@@ -229,7 +455,7 @@
             return;
         }
         mBadgeImage.setImageDrawable(drawable);
-        if (drawable != null && mContentView!= null && mContentView.getVisibility() != GONE) {
+        if (drawable != null) {
             mBadgeImage.setVisibility(View.VISIBLE);
         } else {
             mBadgeImage.setVisibility(View.GONE);
@@ -250,8 +476,8 @@
     private void fadeIn() {
         mImageView.setAlpha(0f);
         if (mAttachedToWindow) {
-            mImageView.animate().alpha(1f).setDuration(mImageView.getResources().getInteger(
-                    android.R.integer.config_shortAnimTime));
+            mImageView.animate().alpha(1f)
+                    .setDuration(mImageView.getResources().getInteger(android.R.integer.config_shortAnimTime));
         }
     }
 
@@ -276,4 +502,5 @@
         mImageView.setAlpha(1f);
         super.onDetachedFromWindow();
     }
+
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java b/v17/leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java
new file mode 100644
index 0000000..4691ad2
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java
@@ -0,0 +1,47 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.widget.EditText;
+import android.view.KeyEvent;
+
+/**
+ * Interface for an EditText subclass that can delegate calls to onKeyPreIme up to a registered
+ * listener.
+ * <p>
+ * Used in editable actions within {@link android.support.v17.leanback.app.GuidedStepFragment} to
+ * allow for custom back key handling. Specifically, this is used to implement the behavior that
+ * dismissing the IME also clears edit text focus. Clients who need to supply custom layouts for
+ * {@link GuidedActionsStylist} with their own EditText classes should satisfy this interface in
+ * order to inherit this behavior.
+ */
+public interface ImeKeyMonitor {
+
+    /**
+     * Listener interface for key events intercepted pre-IME by edit text objects.
+     */
+    public interface ImeKeyListener {
+        /**
+         * Callback invoked from EditText's onKeyPreIme method override. Returning true tells the
+         * caller that the key event is handled and should not be propagated.
+         */
+        public abstract boolean onKeyPreIme(EditText editText, int keyCode, KeyEvent event);
+    }
+
+    /**
+     * Set the listener for this edit text object. The listener's onKeyPreIme method will be
+     * invoked from the host edit text's onKeyPreIme method.
+     */
+    public void setImeKeyListener(ImeKeyListener listener);
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
index 8e3aea3..57e8bfe 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
@@ -177,11 +177,15 @@
      * Sets the {@link ObjectAdapter}.
      */
     public void setAdapter(ObjectAdapter adapter) {
+        if (adapter == mAdapter) {
+            return;
+        }
         if (mAdapter != null) {
             mAdapter.unregisterObserver(mDataObserver);
         }
         mAdapter = adapter;
         if (mAdapter == null) {
+            notifyDataSetChanged();
             return;
         }
 
@@ -189,6 +193,7 @@
         if (hasStableIds() != mAdapter.hasStableIds()) {
             setHasStableIds(mAdapter.hasStableIds());
         }
+        notifyDataSetChanged();
     }
 
     /**
@@ -233,7 +238,7 @@
 
     @Override
     public int getItemCount() {
-        return mAdapter.size();
+        return mAdapter != null ? mAdapter.size() : 0;
     }
 
     @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
new file mode 100644
index 0000000..19e6e9a
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * A wrapper class working with {@link ItemBridgeAdapter} to wrap item view in a
+ * {@link ShadowOverlayContainer}.  The ShadowOverlayContainer is created from conditions
+ * of {@link ShadowOverlayHelper}.
+ */
+public class ItemBridgeAdapterShadowOverlayWrapper extends ItemBridgeAdapter.Wrapper {
+
+    private final ShadowOverlayHelper mHelper;
+
+    public ItemBridgeAdapterShadowOverlayWrapper(ShadowOverlayHelper helper) {
+        mHelper = helper;
+    }
+
+    @Override
+    public View createWrapper(View root) {
+        Context context = root.getContext();
+        ShadowOverlayContainer wrapper = mHelper.createShadowOverlayContainer(context);
+        return wrapper;
+    }
+    @Override
+    public void wrap(View wrapper, View wrapped) {
+        ((ShadowOverlayContainer) wrapper).wrap(wrapped);
+    }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
index 9e588eb..5540f78 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
@@ -15,8 +15,10 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.system.Settings;
+import android.support.v17.leanback.transition.TransitionHelper;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
@@ -96,6 +98,16 @@
         }
 
         @Override
+        protected void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) {
+            if (viewHolder.itemView instanceof ViewGroup) {
+                TransitionHelper.setTransitionGroup((ViewGroup) viewHolder.itemView, true);
+            }
+            if (mShadowOverlayHelper != null) {
+                mShadowOverlayHelper.onViewCreated(viewHolder.itemView);
+            }
+        }
+
+        @Override
         public void onBind(final ItemBridgeAdapter.ViewHolder viewHolder) {
             // Only when having an OnItemClickListner, we will attach the OnClickListener.
             if (mRowViewHolder.getOnItemViewClickedListener() != null) {
@@ -122,9 +134,9 @@
 
         @Override
         public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
-            if (needsDefaultListSelectEffect()) {
+            if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) {
                 int dimmedColor = mRowViewHolder.mColorDimmer.getPaint().getColor();
-                ((ShadowOverlayContainer) viewHolder.itemView).setOverlayColor(dimmedColor);
+                mShadowOverlayHelper.setOverlayColor(viewHolder.itemView, dimmedColor);
             }
             mRowViewHolder.syncActivatedStatus(viewHolder.itemView);
         }
@@ -144,7 +156,10 @@
     private boolean mShadowEnabled = true;
     private int mBrowseRowsFadingEdgeLength = -1;
     private boolean mRoundedCornersEnabled = true;
+    private boolean mKeepChildForeground = true;
     private HashMap<Presenter, Integer> mRecycledPoolSize = new HashMap<Presenter, Integer>();
+    private ShadowOverlayHelper mShadowOverlayHelper;
+    private ItemBridgeAdapter.Wrapper mShadowOverlayWrapper;
 
     private static int sSelectedRowTopPadding;
     private static int sExpandedSelectedRowTopPadding;
@@ -253,44 +268,34 @@
         return mUseFocusDimmer;
     }
 
-    private ItemBridgeAdapter.Wrapper mCardWrapper = new ItemBridgeAdapter.Wrapper() {
-        @Override
-        public View createWrapper(View root) {
-            ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext());
-            wrapper.setLayoutParams(
-                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-            if (isUsingZOrder(root.getContext())) {
-                wrapper.useDynamicShadow();
-            } else {
-                wrapper.useStaticShadow();
-            }
-            wrapper.initialize(needsDefaultShadow(),
-                    needsDefaultListSelectEffect(),
-                    areChildRoundedCornersEnabled());
-            return wrapper;
-        }
-        @Override
-        public void wrap(View wrapper, View wrapped) {
-            ((ShadowOverlayContainer) wrapper).wrap(wrapped);
-        }
-    };
-
     @Override
     protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) {
         super.initializeRowViewHolder(holder);
         final ViewHolder rowViewHolder = (ViewHolder) holder;
+        Context context = holder.view.getContext();
+        if (mShadowOverlayHelper == null) {
+            mShadowOverlayHelper = new ShadowOverlayHelper.Builder()
+                    .needsOverlay(needsDefaultListSelectEffect())
+                    .needsShadow(needsDefaultShadow())
+                    .needsRoundedCorner(areChildRoundedCornersEnabled())
+                    .preferZOrder(isUsingZOrder(context))
+                    .keepForegroundDrawable(mKeepChildForeground)
+                    .options(createShadowOverlayOptions())
+                    .build(context);
+            if (mShadowOverlayHelper.needsWrapper()) {
+                mShadowOverlayWrapper = new ItemBridgeAdapterShadowOverlayWrapper(
+                        mShadowOverlayHelper);
+            }
+        }
         rowViewHolder.mItemBridgeAdapter = new ListRowPresenterItemBridgeAdapter(rowViewHolder);
-        if (needsDefaultListSelectEffect() || needsDefaultShadow()
-                || areChildRoundedCornersEnabled()) {
-            rowViewHolder.mItemBridgeAdapter.setWrapper(mCardWrapper);
-        }
-        if (needsDefaultShadow()) {
-            ShadowOverlayContainer.prepareParentForShadow(rowViewHolder.mGridView);
-        }
+        // set wrapper if needed
+        rowViewHolder.mItemBridgeAdapter.setWrapper(mShadowOverlayWrapper);
+        mShadowOverlayHelper.prepareParentForShadow(rowViewHolder.mGridView);
+
         FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter,
                 mFocusZoomFactor, mUseFocusDimmer);
-        rowViewHolder.mGridView.setFocusDrawingOrderEnabled(
-                !isUsingZOrder(rowViewHolder.getGridView().getContext()));
+        rowViewHolder.mGridView.setFocusDrawingOrderEnabled(mShadowOverlayHelper.getShadowType()
+                == ShadowOverlayHelper.SHADOW_STATIC);
         rowViewHolder.mGridView.setOnChildSelectedListener(
                 new OnChildSelectedListener() {
             @Override
@@ -545,7 +550,7 @@
      * Subclass may return false to disable.
      */
     public boolean isUsingDefaultShadow() {
-        return ShadowOverlayContainer.supportsShadow();
+        return ShadowOverlayHelper.supportsShadow();
     }
 
     /**
@@ -554,8 +559,7 @@
      * and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false.
      */
     public boolean isUsingZOrder(Context context) {
-        return ShadowOverlayContainer.supportsDynamicShadow() &&
-                !Settings.getInstance(context).preferStaticShadows();
+        return !Settings.getInstance(context).preferStaticShadows();
     }
 
     /**
@@ -595,9 +599,41 @@
         return isUsingDefaultShadow() && getShadowEnabled();
     }
 
-    @Override
-    public boolean canDrawOutOfBounds() {
-        return needsDefaultShadow();
+    /**
+     * When ListRowPresenter applies overlay color on the child,  it may change child's foreground
+     * Drawable.  If application uses child's foreground for other purposes such as ripple effect,
+     * it needs tell ListRowPresenter to keep the child's foreground.  The default value is true.
+     *
+     * @param keep true if keep foreground of child of this row, false ListRowPresenter might change
+     *             the foreground of the child.
+     */
+    public final void setKeepChildForeground(boolean keep) {
+        mKeepChildForeground = keep;
+    }
+
+    /**
+     * Returns true if keeps foreground of child of this row, false otherwise.  When
+     * ListRowPresenter applies overlay color on the child,  it may change child's foreground
+     * Drawable.  If application uses child's foreground for other purposes such as ripple effect,
+     * it needs tell ListRowPresenter to keep the child's foreground.  The default value is true.
+     *
+     * @return true if keeps foreground of child of this row, false otherwise.
+     */
+    public final boolean isKeepChildForeground() {
+        return mKeepChildForeground;
+    }
+
+    /**
+     * Create ShadowOverlayHelper Options.  Subclass may override.
+     * e.g.
+     * <code>
+     * return new ShadowOverlayHelper.Options().roundedCornerRadius(10);
+     * </code>
+     *
+     * @return The options to be used for shadow, overlay and rouded corner.
+     */
+    protected ShadowOverlayHelper.Options createShadowOverlayOptions() {
+        return ShadowOverlayHelper.Options.DEFAULT;
     }
 
     /**
@@ -615,12 +651,11 @@
     @Override
     protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
         super.onSelectLevelChanged(holder);
-        if (needsDefaultListSelectEffect()) {
+        if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) {
             ViewHolder vh = (ViewHolder) holder;
             int dimmedColor = vh.mColorDimmer.getPaint().getColor();
             for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) {
-                ShadowOverlayContainer wrapper = (ShadowOverlayContainer) vh.mGridView.getChildAt(i);
-                wrapper.setOverlayColor(dimmedColor);
+                mShadowOverlayHelper.setOverlayColor(vh.mGridView.getChildAt(i), dimmedColor);
             }
             if (vh.mGridView.getFadingLeftEdge()) {
                 vh.mGridView.invalidate();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
index f1db00b..17225f8 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
@@ -58,7 +58,7 @@
         final TextView mCurrentTime;
         final TextView mTotalTime;
         final ProgressBar mProgressBar;
-        int mCurrentTimeInSeconds;
+        int mCurrentTimeInSeconds = -1;
         StringBuilder mTotalTimeStringBuilder = new StringBuilder();
         StringBuilder mCurrentTimeStringBuilder = new StringBuilder();
         int mCurrentTimeMarginStart;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java
index e1c5979..35a5b67 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java
@@ -13,8 +13,7 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
+import android.support.v17.leanback.R;
 import android.os.Build;
 import android.view.View;
 
@@ -24,7 +23,7 @@
 final class RoundedRectHelper {
 
     private final static RoundedRectHelper sInstance = new RoundedRectHelper();
-    private Impl mImpl;
+    private final Impl mImpl;
 
     /**
      * Returns an instance of the helper.
@@ -33,15 +32,27 @@
         return sInstance;
     }
 
+    public static boolean supportsRoundedCorner() {
+        return Build.VERSION.SDK_INT >= 21;
+    }
+
+    /**
+     * Sets or removes a rounded rectangle outline on the given view.
+     */
+    public void setClipToRoundedOutline(View view, boolean clip, int radius) {
+        mImpl.setClipToRoundedOutline(view, clip, radius);
+    }
+
     /**
      * Sets or removes a rounded rectangle outline on the given view.
      */
     public void setClipToRoundedOutline(View view, boolean clip) {
-        mImpl.setClipToRoundedOutline(view, clip);
+        mImpl.setClipToRoundedOutline(view, clip, view.getResources().getDimensionPixelSize(
+                R.dimen.lb_rounded_rect_corner_radius));
     }
 
     static interface Impl {
-        public void setClipToRoundedOutline(View view, boolean clip);
+        public void setClipToRoundedOutline(View view, boolean clip, int radius);
     }
 
     /**
@@ -49,7 +60,7 @@
      */
     private static final class StubImpl implements Impl {
         @Override
-        public void setClipToRoundedOutline(View view, boolean clip) {
+        public void setClipToRoundedOutline(View view, boolean clip, int radius) {
             // Not supported
         }
     }
@@ -59,13 +70,13 @@
      */
     private static final class Api21Impl implements Impl {
         @Override
-        public void setClipToRoundedOutline(View view, boolean clip) {
-            RoundedRectHelperApi21.setClipToRoundedOutline(view, clip);
+        public void setClipToRoundedOutline(View view, boolean clip, int radius) {
+            RoundedRectHelperApi21.setClipToRoundedOutline(view, clip, radius);
         }
     }
 
     private RoundedRectHelper() {
-        if (Build.VERSION.SDK_INT >= 21) {
+        if (supportsRoundedCorner()) {
             mImpl = new Api21Impl();
         } else {
             mImpl = new StubImpl();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
index 4f078f1..cb1f2ac7 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
@@ -565,13 +565,6 @@
         return mHeaderPresenter != null || needsDefaultSelectEffect();
     }
 
-    /**
-     * Returns true if the Row view can draw outside its bounds.
-     */
-    public boolean canDrawOutOfBounds() {
-        return false;
-    }
-
     @Override
     public final void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
         onBindRowViewHolder(getRowViewHolder(viewHolder), item);
@@ -642,12 +635,16 @@
      * Changes the visibility of views.  The entrance transition will be run against the views that
      * change visibilities.  A subclass may override and begin with calling
      * super.setEntranceTransitionState().  This method is called by the fragment,
-     * it should not call it directly by the application.
+     * it should not be called directly by the application.
+     *
+     * @param holder         The ViewHolder of the row.
+     * @param afterEntrance  true if children of row participating in entrance transition
+     *                       should be set to visible, false otherwise.
      */
-    public void setEntranceTransitionState(ViewHolder holder, boolean afterTransition) {
+    public void setEntranceTransitionState(ViewHolder holder, boolean afterEntrance) {
         if (holder.mHeaderViewHolder != null &&
                 holder.mHeaderViewHolder.view.getVisibility() != View.GONE) {
-            holder.mHeaderViewHolder.view.setVisibility(afterTransition ?
+            holder.mHeaderViewHolder.view.setVisibility(afterEntrance ?
                     View.VISIBLE : View.INVISIBLE);
         }
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
index acdebcb..1c3835f 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
@@ -406,15 +406,23 @@
      * @param completions list of completions shown in the IME, can be null or empty to clear them
      */
     public void displayCompletions(List<String> completions) {
-        List<CompletionInfo> infos = new ArrayList<CompletionInfo>();
+        List<CompletionInfo> infos = new ArrayList<>();
         if (null != completions) {
             for (String completion : completions) {
                 infos.add(new CompletionInfo(infos.size(), infos.size(), completion));
             }
         }
+        CompletionInfo[] array = new CompletionInfo[infos.size()];
+        displayCompletions(infos.toArray(array));
+    }
 
-        mInputMethodManager.displayCompletions(mSearchTextEditor,
-                infos.toArray(new CompletionInfo[] {}));
+    /**
+     * Updates the completion list shown by the IME
+     *
+     * @param completions list of completions shown in the IME, can be null or empty to clear them
+     */
+    public void displayCompletions(CompletionInfo[] completions) {
+        mInputMethodManager.displayCompletions(mSearchTextEditor, completions);
     }
 
     /**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java
index be70575..aec9673 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java
@@ -14,7 +14,6 @@
 package android.support.v17.leanback.widget;
 
 import android.os.Build;
-import android.view.ViewGroup;
 import android.view.View;
 
 
@@ -32,7 +31,7 @@
      */
     static interface ShadowHelperVersionImpl {
         public Object addDynamicShadow(
-                ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners);
+                View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius);
         public void setZ(View view, float z);
         public void setShadowFocusLevel(Object impl, float level);
     }
@@ -43,7 +42,7 @@
     private static final class ShadowHelperStubImpl implements ShadowHelperVersionImpl {
         @Override
         public Object addDynamicShadow(
-                ViewGroup shadowContainer, float focusedZ, float unfocusedZ, boolean roundedCorners) {
+                View shadowContainer, float focusedZ, float unfocusedZ, int roundedCornerRadius) {
             // do nothing
             return null;
         }
@@ -65,9 +64,9 @@
     private static final class ShadowHelperApi21Impl implements ShadowHelperVersionImpl {
         @Override
         public Object addDynamicShadow(
-                ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners) {
+                View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius) {
             return ShadowHelperApi21.addDynamicShadow(
-                    shadowContainer, unfocusedZ, focusedZ, roundedCorners);
+                    shadowContainer, unfocusedZ, focusedZ, roundedCornerRadius);
         }
 
         @Override
@@ -102,8 +101,8 @@
     }
 
     public Object addDynamicShadow(
-            ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners) {
-        return mImpl.addDynamicShadow(shadowContainer, unfocusedZ, focusedZ, roundedCorners);
+            View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius) {
+        return mImpl.addDynamicShadow(shadowContainer, unfocusedZ, focusedZ, roundedCornerRadius);
     }
 
     public void setShadowFocusLevel(Object impl, float level) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
index e367494..fdb7c71 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
@@ -20,11 +20,16 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.Rect;
 
 /**
  * Provides an SDK version-independent wrapper to support shadows, color overlays, and rounded
- * corners.
+ * corners.  It's not always preferred to create a ShadowOverlayContainer, use
+ * {@link ShadowOverlayHelper} instead.
  * <p>
  * {@link #prepareParentForShadow(ViewGroup)} must be called on parent of container
  * before using shadow.  Depending on sdk version, optical bounds might be applied
@@ -46,41 +51,52 @@
  * Call {@link #setOverlayColor(int)} to control overlay color.
  * </p>
  */
-public class ShadowOverlayContainer extends ViewGroup {
+public class ShadowOverlayContainer extends FrameLayout {
 
     /**
      * No shadow.
      */
-    public static final int SHADOW_NONE = 1;
+    public static final int SHADOW_NONE = ShadowOverlayHelper.SHADOW_NONE;
 
     /**
      * Shadows are fixed.
      */
-    public static final int SHADOW_STATIC = 2;
+    public static final int SHADOW_STATIC = ShadowOverlayHelper.SHADOW_STATIC;
 
     /**
      * Shadows depend on the size, shape, and position of the view.
      */
-    public static final int SHADOW_DYNAMIC = 3;
+    public static final int SHADOW_DYNAMIC = ShadowOverlayHelper.SHADOW_DYNAMIC;
 
     private boolean mInitialized;
-    private View mColorDimOverlay;
     private Object mShadowImpl;
     private View mWrappedView;
     private boolean mRoundedCorners;
     private int mShadowType = SHADOW_NONE;
     private float mUnfocusedZ;
     private float mFocusedZ;
+    private int mRoundedCornerRadius;
     private static final Rect sTempRect = new Rect();
+    private Paint mOverlayPaint;
+    private int mOverlayColor;
 
+    /**
+     * Create ShadowOverlayContainer and auto select shadow type.
+     */
     public ShadowOverlayContainer(Context context) {
         this(context, null, 0);
     }
 
+    /**
+     * Create ShadowOverlayContainer and auto select shadow type.
+     */
     public ShadowOverlayContainer(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
+    /**
+     * Create ShadowOverlayContainer and auto select shadow type.
+     */
     public ShadowOverlayContainer(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         useStaticShadow();
@@ -88,6 +104,18 @@
     }
 
     /**
+     * Create ShadowOverlayContainer with specific shadowType.
+     */
+    ShadowOverlayContainer(Context context,
+            int shadowType, boolean hasColorDimOverlay,
+            float unfocusedZ, float focusedZ, int roundedCornerRadius) {
+        super(context);
+        mUnfocusedZ = unfocusedZ;
+        mFocusedZ = focusedZ;
+        initialize(shadowType, hasColorDimOverlay, roundedCornerRadius);
+    }
+
+    /**
      * Return true if the platform sdk supports shadow.
      */
     public static boolean supportsShadow() {
@@ -155,7 +183,7 @@
 
     /**
      * Initialize shadows, color overlay.
-     * @deprecated use {@link #initialize(boolean, boolean, boolean)} instead.
+     * @deprecated use {@link ShadowOverlayHelper#createShadowOverlayContainer(Context)} instead.
      */
     @Deprecated
     public void initialize(boolean hasShadow, boolean hasColorDimOverlay) {
@@ -164,29 +192,62 @@
 
     /**
      * Initialize shadows, color overlay, and rounded corners.  All are optional.
+     * Shadow type are auto-selected based on {@link #useStaticShadow()} and
+     * {@link #useDynamicShadow()} call.
+     * @deprecated use {@link ShadowOverlayHelper#createShadowOverlayContainer(Context)} instead.
      */
+    @Deprecated
     public void initialize(boolean hasShadow, boolean hasColorDimOverlay, boolean roundedCorners) {
+        int shadowType;
+        if (!hasShadow) {
+            shadowType = SHADOW_NONE;
+        } else {
+            shadowType = mShadowType;
+        }
+        int roundedCornerRadius = roundedCorners ? getContext().getResources().getDimensionPixelSize(
+                R.dimen.lb_rounded_rect_corner_radius) : 0;
+        initialize(shadowType, hasColorDimOverlay, roundedCornerRadius);
+    }
+
+    /**
+     * Initialize shadows, color overlay, and rounded corners.  All are optional.
+     */
+    void initialize(int shadowType, boolean hasColorDimOverlay, int roundedCornerRadius) {
         if (mInitialized) {
             throw new IllegalStateException();
         }
         mInitialized = true;
-        if (hasShadow) {
-            switch (mShadowType) {
-                case SHADOW_DYNAMIC:
-                    mShadowImpl = ShadowHelper.getInstance().addDynamicShadow(
-                            this, mUnfocusedZ, mFocusedZ, roundedCorners);
-                    break;
-                case SHADOW_STATIC:
-                    mShadowImpl = StaticShadowHelper.getInstance().addStaticShadow(
-                            this, roundedCorners);
-                    break;
-            }
+        mRoundedCornerRadius = roundedCornerRadius;
+        mRoundedCorners = roundedCornerRadius > 0;
+        mShadowType = shadowType;
+        switch (mShadowType) {
+            case SHADOW_DYNAMIC:
+                mShadowImpl = ShadowHelper.getInstance().addDynamicShadow(
+                        this, mUnfocusedZ, mFocusedZ, mRoundedCornerRadius);
+                break;
+            case SHADOW_STATIC:
+                mShadowImpl = StaticShadowHelper.getInstance().addStaticShadow(this);
+                break;
         }
-        mRoundedCorners = roundedCorners;
         if (hasColorDimOverlay) {
-            mColorDimOverlay = LayoutInflater.from(getContext())
-                    .inflate(R.layout.lb_card_color_overlay, this, false);
-            addView(mColorDimOverlay);
+            setWillNotDraw(false);
+            mOverlayColor = Color.TRANSPARENT;
+            mOverlayPaint = new Paint();
+            mOverlayPaint.setColor(mOverlayColor);
+            mOverlayPaint.setStyle(Paint.Style.FILL);
+        } else {
+            setWillNotDraw(true);
+            mOverlayPaint = null;
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        if (mOverlayPaint != null && mOverlayColor != Color.TRANSPARENT) {
+            canvas.drawRect(mWrappedView.getLeft(), mWrappedView.getTop(),
+                    mWrappedView.getRight(), mWrappedView.getBottom(),
+                    mOverlayPaint);
         }
     }
 
@@ -195,19 +256,7 @@
      */
     public void setShadowFocusLevel(float level) {
         if (mShadowImpl != null) {
-            if (level < 0f) {
-                level = 0f;
-            } else if (level > 1f) {
-                level = 1f;
-            }
-            switch (mShadowType) {
-                case SHADOW_DYNAMIC:
-                    ShadowHelper.getInstance().setShadowFocusLevel(mShadowImpl, level);
-                    break;
-                case SHADOW_STATIC:
-                    StaticShadowHelper.getInstance().setShadowFocusLevel(mShadowImpl, level);
-                    break;
-            }
+            ShadowOverlayHelper.setShadowFocusLevel(mShadowImpl, mShadowType, level);
         }
     }
 
@@ -215,8 +264,12 @@
      * Set color (with alpha) of the overlay.
      */
     public void setOverlayColor(@ColorInt int overlayColor) {
-        if (mColorDimOverlay != null) {
-            mColorDimOverlay.setBackgroundColor(overlayColor);
+        if (mOverlayPaint != null) {
+            if (overlayColor != mOverlayColor) {
+                mOverlayColor = overlayColor;
+                mOverlayPaint.setColor(overlayColor);
+                invalidate();
+            }
         }
     }
 
@@ -227,15 +280,27 @@
         if (!mInitialized || mWrappedView != null) {
             throw new IllegalStateException();
         }
-        if (mColorDimOverlay != null) {
-            addView(view, indexOfChild(mColorDimOverlay));
+        ViewGroup.LayoutParams lp = view.getLayoutParams();
+        if (lp != null) {
+            // if wrapped view has layout params, inherit everything but width/height.
+            // Wrapped view is assigned a FrameLayout.LayoutParams with width and height only.
+            // Margins, etc are assigned to the wrapper and take effect in parent container.
+            ViewGroup.LayoutParams wrapped_lp = new FrameLayout.LayoutParams(lp.width, lp.height);
+            // Uses MATCH_PARENT for MATCH_PARENT, WRAP_CONTENT for WRAP_CONTENT and fixed size,
+            // App can still change wrapped view fixed width/height afterwards.
+            lp.width = lp.width == LayoutParams.MATCH_PARENT ?
+                    LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
+            lp.height = lp.height == LayoutParams.MATCH_PARENT ?
+                    LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
+            this.setLayoutParams(lp);
+            addView(view, wrapped_lp);
         } else {
             addView(view);
         }
-        mWrappedView = view;
-        if (mRoundedCorners) {
-            RoundedRectHelper.getInstance().setClipToRoundedOutline(mWrappedView, true);
+        if (mRoundedCorners && mShadowType == SHADOW_STATIC) {
+            RoundedRectHelper.getInstance().setClipToRoundedOutline(view, true);
         }
+        mWrappedView = view;
     }
 
     /**
@@ -246,67 +311,9 @@
     }
 
     @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mWrappedView == null) {
-            throw new IllegalStateException();
-        }
-        // padding and child margin are not supported.
-        // first measure the wrapped view, then measure the shadow view and/or overlay view.
-        int childWidthMeasureSpec, childHeightMeasureSpec;
-        LayoutParams lp = mWrappedView.getLayoutParams();
-        if (lp.width == LayoutParams.MATCH_PARENT) {
-            childWidthMeasureSpec = MeasureSpec.makeMeasureSpec
-                    (MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY);
-        } else {
-            childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
-        }
-        if (lp.height == LayoutParams.MATCH_PARENT) {
-            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec
-                    (MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
-        } else {
-            childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
-        }
-        mWrappedView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-
-        int measuredWidth = mWrappedView.getMeasuredWidth();
-        int measuredHeight = mWrappedView.getMeasuredHeight();
-
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child == mWrappedView) {
-                continue;
-            }
-            lp = child.getLayoutParams();
-            if (lp.width == LayoutParams.MATCH_PARENT) {
-                childWidthMeasureSpec = MeasureSpec.makeMeasureSpec
-                        (measuredWidth, MeasureSpec.EXACTLY);
-            } else {
-                childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
-            }
-
-            if (lp.height == LayoutParams.MATCH_PARENT) {
-                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec
-                        (measuredHeight, MeasureSpec.EXACTLY);
-            } else {
-                childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
-            }
-            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-        }
-        setMeasuredDimension(measuredWidth, measuredHeight);
-    }
-
-    @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                final int width = child.getMeasuredWidth();
-                final int height = child.getMeasuredHeight();
-                child.layout(0, 0, width, height);
-            }
-        }
-        if (mWrappedView != null) {
+        super.onLayout(changed, l, t, r, b);
+        if (changed && mWrappedView != null) {
             sTempRect.left = (int) mWrappedView.getPivotX();
             sTempRect.top = (int) mWrappedView.getPivotY();
             offsetDescendantRectToMyCoords(mWrappedView, sTempRect);
@@ -315,4 +322,8 @@
         }
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java
new file mode 100644
index 0000000..5f942c6
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java
@@ -0,0 +1,467 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.system.Settings;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.View;
+
+
+/**
+ * ShadowOverlayHelper is a helper class for shadow, overlay color and rounded corner.
+ * There are many choices to implement Shadow, overlay color.
+ * Initialize it with ShadowOverlayHelper.Builder and it decides the best strategy based
+ * on options user choose and current platform version.
+ *
+ * <li> For shadow:  it may use 9-patch with opticalBounds or Z-value based shadow for
+ *                   API >= 21.  When 9-patch is used, it requires a ShadowOverlayContainer
+ *                   to include 9-patch views.
+ * <li> For overlay: it may use ShadowOverlayContainer which overrides draw() or it may
+ *                   use setForeground(new ColorDrawable()) for API>=23.  The foreground support
+ *                   might be disabled if rounded corner is applied due to performance reason.
+ * <li> For rounded-corner:  it uses a ViewOutlineProvider for API>=21.
+ *
+ * There are two different strategies: use Wrapper with a ShadowOverlayContainer;
+ * or apply rounded corner, overlay and rounded-corner to the view itself.  Below is an example
+ * of how helper is used.
+ *
+ * <code>
+ * ShadowOverlayHelper mHelper = new ShadowOverlayHelper.Builder().
+ *         .needsOverlay(true).needsRoundedCorner(true).needsShadow(true)
+ *         .build();
+ * mHelper.prepareParentForShadow(parentView); // apply optical-bounds for 9-patch shadow.
+ * mHelper.setOverlayColor(view, Color.argb(0x80, 0x80, 0x80, 0x80));
+ * mHelper.setShadowFocusLevel(view, 1.0f);
+ * ...
+ * View initializeView(View view) {
+ *     if (mHelper.needsWrapper()) {
+ *         ShadowOverlayContainer wrapper = mHelper.createShadowOverlayContainer(context);
+ *         wrapper.wrap(view);
+ *         return wrapper;
+ *     } else {
+ *         mHelper.onViewCreated(view);
+ *         return view;
+ *     }
+ * }
+ * ...
+ *
+ * </code>
+ */
+public final class ShadowOverlayHelper {
+
+    /**
+     * Builder for creating ShadowOverlayHelper.
+     */
+    public static final class Builder {
+
+        private boolean needsOverlay;
+        private boolean needsRoundedCorner;
+        private boolean needsShadow;
+        private boolean preferZOrder = true;
+        private boolean keepForegroundDrawable;
+        private Options options = Options.DEFAULT;
+
+        /**
+         * Set if needs overlay color.
+         * @param needsOverlay   True if needs overlay.
+         * @return  The Builder object itself.
+         */
+        public Builder needsOverlay(boolean needsOverlay) {
+            this.needsOverlay = needsOverlay;
+            return this;
+        }
+
+        /**
+         * Set if needs shadow.
+         * @param needsShadow   True if needs shadow.
+         * @return  The Builder object itself.
+         */
+        public Builder needsShadow(boolean needsShadow) {
+            this.needsShadow = needsShadow;
+            return this;
+        }
+
+        /**
+         * Set if needs rounded corner.
+         * @param needsRoundedCorner   True if needs rounded corner.
+         * @return  The Builder object itself.
+         */
+        public Builder needsRoundedCorner(boolean needsRoundedCorner) {
+            this.needsRoundedCorner = needsRoundedCorner;
+            return this;
+        }
+
+        /**
+         * Set if prefer z-order shadow.  On old devices,  z-order shadow might be slow,
+         * set to false to fall back to static 9-patch shadow.  Recommend to read
+         * from system wide Setting value: see {@link Settings}.
+         *
+         * @param preferZOrder   True if prefer Z shadow.  Default is true.
+         * @return The Builder object itself.
+         */
+        public Builder preferZOrder(boolean preferZOrder) {
+            this.preferZOrder = preferZOrder;
+            return this;
+        }
+
+        /**
+         * Set if not using foreground drawable for overlay color.  For example if
+         * the view has already assigned a foreground drawable for other purposes.
+         * When it's true, helper will use a ShadowOverlayContainer for overlay color.
+         *
+         * @param keepForegroundDrawable   True to keep the original foreground drawable.
+         * @return The Builder object itself.
+         */
+        public Builder keepForegroundDrawable(boolean keepForegroundDrawable) {
+            this.keepForegroundDrawable = keepForegroundDrawable;
+            return this;
+        }
+
+        /**
+         * Set option values e.g. Shadow Z value, rounded corner radius.
+         *
+         * @param options   The Options object to create ShadowOverlayHelper.
+         */
+        public Builder options(Options options) {
+            this.options = options;
+            return this;
+        }
+
+        /**
+         * Create ShadowOverlayHelper object
+         * @param context    The context uses to read Resources settings.
+         * @return           The ShadowOverlayHelper object.
+         */
+        public ShadowOverlayHelper build(Context context) {
+            final ShadowOverlayHelper helper = new ShadowOverlayHelper();
+            helper.mNeedsOverlay = needsOverlay;
+            helper.mNeedsRoundedCorner = needsRoundedCorner && supportsRoundedCorner();
+            helper.mNeedsShadow = needsShadow && supportsShadow();
+
+            if (helper.mNeedsRoundedCorner) {
+                helper.setupRoundedCornerRadius(options, context);
+            }
+
+            // figure out shadow type and if we need use wrapper:
+            if (helper.mNeedsShadow) {
+                // if static shadow is prefered or dynamic shadow is not supported,
+                // use static shadow,  otherwise use dynamic shadow.
+                if (!preferZOrder || !supportsDynamicShadow()) {
+                    helper.mShadowType = SHADOW_STATIC;
+                    // static shadow requires ShadowOverlayContainer to support crossfading
+                    // of two shadow views.
+                    helper.mNeedsWrapper = true;
+                } else {
+                    helper.mShadowType = SHADOW_DYNAMIC;
+                    helper.setupDynamicShadowZ(options, context);
+                    helper.mNeedsWrapper = ((!supportsForeground() || keepForegroundDrawable)
+                            && helper.mNeedsOverlay);
+                }
+            } else {
+                helper.mShadowType = SHADOW_NONE;
+                helper.mNeedsWrapper = ((!supportsForeground() || keepForegroundDrawable)
+                        && helper.mNeedsOverlay);
+            }
+
+            return helper;
+        }
+
+    }
+
+    /**
+     * Option values for ShadowOverlayContainer.
+     */
+    public static final class Options {
+
+        /**
+         * Default Options for values.
+         */
+        public static final Options DEFAULT = new Options();
+
+        private int roundedCornerRadius = 0; // 0 for default value
+        private float dynamicShadowUnfocusedZ = -1; // < 0 for default value
+        private float dynamicShadowFocusedZ = -1;   // < 0 for default value
+        /**
+         * Set value of rounded corner radius.
+         *
+         * @param roundedCornerRadius   Number of pixels of rounded corner radius.
+         *                              Set to 0 to use default settings.
+         * @return  The Options object itself.
+         */
+        public Options roundedCornerRadius(int roundedCornerRadius){
+            this.roundedCornerRadius = roundedCornerRadius;
+            return this;
+        }
+
+        /**
+         * Set value of focused and unfocused Z value for shadow.
+         *
+         * @param unfocusedZ   Number of pixels for unfocused Z value.
+         * @param focusedZ     Number of pixels for foucsed Z value.
+         * @return  The Options object itself.
+         */
+        public Options dynamicShadowZ(float unfocusedZ, float focusedZ){
+            this.dynamicShadowUnfocusedZ = unfocusedZ;
+            this.dynamicShadowFocusedZ = focusedZ;
+            return this;
+        }
+
+        /**
+         * Get radius of rounded corner in pixels.
+         *
+         * @return Radius of rounded corner in pixels.
+         */
+        public final int getRoundedCornerRadius() {
+            return roundedCornerRadius;
+        }
+
+        /**
+         * Get z value of shadow when a view is not focused.
+         *
+         * @return Z value of shadow when a view is not focused.
+         */
+        public final float getDynamicShadowUnfocusedZ() {
+            return dynamicShadowUnfocusedZ;
+        }
+
+        /**
+         * Get z value of shadow when a view is focused.
+         *
+         * @return Z value of shadow when a view is focused.
+         */
+        public final float getDynamicShadowFocusedZ() {
+            return dynamicShadowFocusedZ;
+        }
+    }
+
+    /**
+     * No shadow.
+     */
+    public static final int SHADOW_NONE = 1;
+
+    /**
+     * Shadows are fixed.
+     */
+    public static final int SHADOW_STATIC = 2;
+
+    /**
+     * Shadows depend on the size, shape, and position of the view.
+     */
+    public static final int SHADOW_DYNAMIC = 3;
+
+    int mShadowType = SHADOW_NONE;
+    boolean mNeedsOverlay;
+    boolean mNeedsRoundedCorner;
+    boolean mNeedsShadow;
+    boolean mNeedsWrapper;
+
+    int mRoundedCornerRadius;
+    float mUnfocusedZ;
+    float mFocusedZ;
+
+    /**
+     * Return true if the platform sdk supports shadow.
+     */
+    public static boolean supportsShadow() {
+        return StaticShadowHelper.getInstance().supportsShadow();
+    }
+
+    /**
+     * Returns true if the platform sdk supports dynamic shadows.
+     */
+    public static boolean supportsDynamicShadow() {
+        return ShadowHelper.getInstance().supportsDynamicShadow();
+    }
+
+    /**
+     * Returns true if the platform sdk supports rounded corner through outline.
+     */
+    public static boolean supportsRoundedCorner() {
+        return RoundedRectHelper.supportsRoundedCorner();
+    }
+
+    /**
+     * Returns true if view.setForeground() is supported.
+     */
+    public static boolean supportsForeground() {
+        return ForegroundHelper.supportsForeground();
+    }
+
+    /*
+     * hide from external, should be only created by ShadowOverlayHelper.Options.
+     */
+    ShadowOverlayHelper() {
+    }
+
+    /**
+     * {@link #prepareParentForShadow(ViewGroup)} must be called on parent of container
+     * before using shadow.  Depending on Shadow type, optical bounds might be applied.
+     */
+    public void prepareParentForShadow(ViewGroup parent) {
+        if (mShadowType == SHADOW_STATIC) {
+            StaticShadowHelper.getInstance().prepareParent(parent);
+        }
+    }
+
+    public int getShadowType() {
+        return mShadowType;
+    }
+
+    public boolean needsOverlay() {
+        return mNeedsOverlay;
+    }
+
+    public boolean needsRoundedCorner() {
+        return mNeedsRoundedCorner;
+    }
+
+    /**
+     * Returns true if a "wrapper" ShadowOverlayContainer is needed.
+     * When needsWrapper() is true,  call {@link #createShadowOverlayContainer(Context)}
+     * to create the wrapper.
+     */
+    public boolean needsWrapper() {
+        return mNeedsWrapper;
+    }
+
+    /**
+     * Create ShadowOverlayContainer for this helper.
+     * @param context   Context to create view.
+     * @return          ShadowOverlayContainer.
+     */
+    public ShadowOverlayContainer createShadowOverlayContainer(Context context) {
+        if (!needsWrapper()) {
+            throw new IllegalArgumentException();
+        }
+        return new ShadowOverlayContainer(context, mShadowType, mNeedsOverlay,
+                mUnfocusedZ, mFocusedZ, mRoundedCornerRadius);
+    }
+
+    /**
+     * Set overlay color for view other than ShadowOverlayContainer.
+     * See also {@link ShadowOverlayContainer#setOverlayColor(int)}.
+     */
+    public static void setNoneWrapperOverlayColor(View view, int color) {
+        Drawable d = ForegroundHelper.getInstance().getForeground(view);
+        if (d instanceof ColorDrawable) {
+            ((ColorDrawable) d).setColor(color);
+        } else {
+            ForegroundHelper.getInstance().setForeground(view, new ColorDrawable(color));
+        }
+    }
+
+    /**
+     * Set overlay color for view, it can be a ShadowOverlayContainer if needsWrapper() is true,
+     * or other view type.
+     */
+    public void setOverlayColor(View view, int color) {
+        if (needsWrapper()) {
+            ((ShadowOverlayContainer) view).setOverlayColor(color);
+        } else {
+            setNoneWrapperOverlayColor(view, color);
+        }
+    }
+
+    /**
+     * Must be called when view is created for cases {@link #needsWrapper()} is false.
+     * @param view
+     */
+    public void onViewCreated(View view) {
+        if (!needsWrapper()) {
+            if (!mNeedsShadow) {
+                if (mNeedsRoundedCorner) {
+                    RoundedRectHelper.getInstance().setClipToRoundedOutline(view,
+                            true, mRoundedCornerRadius);
+                }
+            } else {
+                if (mShadowType == SHADOW_DYNAMIC) {
+                    Object tag = ShadowHelper.getInstance().addDynamicShadow(
+                            view, mUnfocusedZ, mFocusedZ, mRoundedCornerRadius);
+                    view.setTag(R.id.lb_shadow_impl, tag);
+                }
+            }
+        }
+    }
+
+    /**
+     * Set shadow focus level (0 to 1). 0 for unfocused, 1 for fully focused.
+     * This is for view other than ShadowOverlayContainer.
+     * See also {@link ShadowOverlayContainer#setShadowFocusLevel(float)}.
+     */
+    public static void setNoneWrapperShadowFocusLevel(View view, float level) {
+        setShadowFocusLevel(getNoneWrapperDyamicShadowImpl(view), SHADOW_DYNAMIC, level);
+    }
+
+    /**
+     * Set shadow focus level (0 to 1). 0 for unfocused, 1 for fully focused.
+     */
+    public void setShadowFocusLevel(View view, float level) {
+        if (needsWrapper()) {
+            ((ShadowOverlayContainer) view).setShadowFocusLevel(level);
+        } else {
+            setShadowFocusLevel(getNoneWrapperDyamicShadowImpl(view), SHADOW_DYNAMIC, level);
+        }
+    }
+
+    void setupDynamicShadowZ(Options options, Context context) {
+        if (options.getDynamicShadowUnfocusedZ() < 0f) {
+            Resources res = context.getResources();
+            mFocusedZ = res.getDimension(R.dimen.lb_material_shadow_focused_z);
+            mUnfocusedZ = res.getDimension(R.dimen.lb_material_shadow_normal_z);
+        } else {
+            mFocusedZ = options.getDynamicShadowFocusedZ();
+            mUnfocusedZ = options.getDynamicShadowUnfocusedZ();
+        }
+    }
+
+    void setupRoundedCornerRadius(Options options, Context context) {
+        if (options.getRoundedCornerRadius() == 0) {
+            Resources res = context.getResources();
+            mRoundedCornerRadius = res.getDimensionPixelSize(
+                        R.dimen.lb_rounded_rect_corner_radius);
+        } else {
+            mRoundedCornerRadius = options.getRoundedCornerRadius();
+        }
+    }
+
+    static Object getNoneWrapperDyamicShadowImpl(View view) {
+        return view.getTag(R.id.lb_shadow_impl);
+    }
+
+    static void setShadowFocusLevel(Object impl, int shadowType, float level) {
+        if (impl != null) {
+            if (level < 0f) {
+                level = 0f;
+            } else if (level > 1f) {
+                level = 1f;
+            }
+            switch (shadowType) {
+                case SHADOW_DYNAMIC:
+                    ShadowHelper.getInstance().setShadowFocusLevel(impl, level);
+                    break;
+                case SHADOW_STATIC:
+                    StaticShadowHelper.getInstance().setShadowFocusLevel(impl, level);
+                    break;
+            }
+        }
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
index 4d8411b..022ff1d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
@@ -34,7 +34,7 @@
      */
     static interface ShadowHelperVersionImpl {
         public void prepareParent(ViewGroup parent);
-        public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners);
+        public Object addStaticShadow(ViewGroup shadowContainer);
         public void setShadowFocusLevel(Object impl, float level);
     }
 
@@ -48,7 +48,7 @@
         }
 
         @Override
-        public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners) {
+        public Object addStaticShadow(ViewGroup shadowContainer) {
             // do nothing
             return null;
         }
@@ -69,8 +69,7 @@
         }
 
         @Override
-        public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners) {
-            // Static shadows are always rounded
+        public Object addStaticShadow(ViewGroup shadowContainer) {
             return ShadowHelperJbmr2.addShadow(shadowContainer);
         }
 
@@ -105,8 +104,8 @@
         mImpl.prepareParent(parent);
     }
 
-    public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners) {
-        return mImpl.addStaticShadow(shadowContainer, roundedCorners);
+    public Object addStaticShadow(ViewGroup shadowContainer) {
+        return mImpl.addStaticShadow(shadowContainer);
     }
 
     public void setShadowFocusLevel(Object impl, float level) {
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 c61087b..9282bb1 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
@@ -36,8 +36,6 @@
     private Object mSceneWithTitle;
     private Object mSceneWithoutTitle;
 
-    static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
-
     // When moving focus off the TitleView, this focus search listener assumes that the view that
     // should take focus comes before the TitleView in a focus search starting at the scene root.
     private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
@@ -68,16 +66,16 @@
 
     private void createTransitions() {
         mTitleUpTransition = LeanbackTransitionHelper.loadTitleOutTransition(
-                mSceneRoot.getContext(), sTransitionHelper);
+                mSceneRoot.getContext());
         mTitleDownTransition = LeanbackTransitionHelper.loadTitleInTransition(
-                mSceneRoot.getContext(), sTransitionHelper);
-        mSceneWithTitle = sTransitionHelper.createScene(mSceneRoot, new Runnable() {
+                mSceneRoot.getContext());
+        mSceneWithTitle = TransitionHelper.createScene(mSceneRoot, new Runnable() {
             @Override
             public void run() {
                 mTitleView.setVisibility(View.VISIBLE);
             }
         });
-        mSceneWithoutTitle = sTransitionHelper.createScene(mSceneRoot, new Runnable() {
+        mSceneWithoutTitle = TransitionHelper.createScene(mSceneRoot, new Runnable() {
             @Override
             public void run() {
                 mTitleView.setVisibility(View.INVISIBLE);
@@ -90,9 +88,9 @@
      */
     public void showTitle(boolean show) {
         if (show) {
-            sTransitionHelper.runTransition(mSceneWithTitle, mTitleDownTransition);
+            TransitionHelper.runTransition(mSceneWithTitle, mTitleDownTransition);
         } else {
-            sTransitionHelper.runTransition(mSceneWithoutTitle, mTitleUpTransition);
+            TransitionHelper.runTransition(mSceneWithoutTitle, mTitleUpTransition);
         }
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
index 16b66cd..7af5ea0 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
@@ -16,6 +16,7 @@
 import android.content.Context;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.system.Settings;
+import android.support.v17.leanback.transition.TransitionHelper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -31,6 +32,17 @@
 
     class VerticalGridItemBridgeAdapter extends ItemBridgeAdapter {
         @Override
+        protected void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) {
+            if (viewHolder.itemView instanceof ViewGroup) {
+                TransitionHelper.setTransitionGroup((ViewGroup) viewHolder.itemView,
+                        true);
+            }
+            if (mShadowOverlayHelper != null) {
+                mShadowOverlayHelper.onViewCreated(viewHolder.itemView);
+            }
+        }
+
+        @Override
         public void onBind(final ItemBridgeAdapter.ViewHolder itemViewHolder) {
             // Only when having an OnItemClickListner, we attach the OnClickListener.
             if (getOnItemViewClickedListener() != null) {
@@ -83,9 +95,12 @@
     private int mFocusZoomFactor;
     private boolean mUseFocusDimmer;
     private boolean mShadowEnabled = true;
+    private boolean mKeepChildForeground = true;
     private OnItemViewSelectedListener mOnItemViewSelectedListener;
     private OnItemViewClickedListener mOnItemViewClickedListener;
     private boolean mRoundedCornersEnabled = true;
+    private ShadowOverlayHelper mShadowOverlayHelper;
+    private ItemBridgeAdapter.Wrapper mShadowOverlayWrapper;
 
     /**
      * Constructs a VerticalGridPresenter with defaults.
@@ -170,7 +185,7 @@
      * Subclass may return false to disable.
      */
     public boolean isUsingDefaultShadow() {
-        return ShadowOverlayContainer.supportsShadow();
+        return ShadowOverlayHelper.supportsShadow();
     }
 
     /**
@@ -194,8 +209,7 @@
      * and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false.
      */
     public boolean isUsingZOrder(Context context) {
-        return ShadowOverlayContainer.supportsDynamicShadow() &&
-                !Settings.getInstance(context).preferStaticShadows();
+        return !Settings.getInstance(context).preferStaticShadows();
     }
 
     final boolean needsDefaultShadow() {
@@ -216,7 +230,6 @@
         return mUseFocusDimmer;
     }
 
-
     @Override
     public final ViewHolder onCreateViewHolder(ViewGroup parent) {
         ViewHolder vh = createGridViewHolder(parent);
@@ -238,21 +251,6 @@
         return new ViewHolder((VerticalGridView) root.findViewById(R.id.browse_grid));
     }
 
-    private ItemBridgeAdapter.Wrapper mWrapper = new ItemBridgeAdapter.Wrapper() {
-        @Override
-        public View createWrapper(View root) {
-            ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext());
-            wrapper.setLayoutParams(
-                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-            wrapper.initialize(needsDefaultShadow(), true, areChildRoundedCornersEnabled());
-            return wrapper;
-        }
-        @Override
-        public void wrap(View wrapper, View wrapped) {
-            ((ShadowOverlayContainer) wrapper).wrap(wrapped);
-        }
-    };
-
     /**
      * Called after a {@link VerticalGridPresenter.ViewHolder} is created.
      * Subclasses may override this method and start by calling
@@ -268,12 +266,25 @@
         vh.getGridView().setNumColumns(mNumColumns);
         vh.mInitialized = true;
 
-        vh.mItemBridgeAdapter.setWrapper(mWrapper);
-        if (needsDefaultShadow() || areChildRoundedCornersEnabled()) {
-            ShadowOverlayContainer.prepareParentForShadow(vh.getGridView());
-            ((ViewGroup) vh.view).setClipChildren(false);
+        Context context = vh.mGridView.getContext();
+        if (mShadowOverlayHelper == null) {
+            mShadowOverlayHelper = new ShadowOverlayHelper.Builder()
+                    .needsOverlay(mUseFocusDimmer)
+                    .needsShadow(needsDefaultShadow())
+                    .needsRoundedCorner(areChildRoundedCornersEnabled())
+                    .preferZOrder(isUsingZOrder(context))
+                    .keepForegroundDrawable(mKeepChildForeground)
+                    .options(createShadowOverlayOptions())
+                    .build(context);
+            if (mShadowOverlayHelper.needsWrapper()) {
+                mShadowOverlayWrapper = new ItemBridgeAdapterShadowOverlayWrapper(
+                        mShadowOverlayHelper);
+            }
         }
-        vh.getGridView().setFocusDrawingOrderEnabled(!isUsingZOrder(vh.getGridView().getContext()));
+        vh.mItemBridgeAdapter.setWrapper(mShadowOverlayWrapper);
+        mShadowOverlayHelper.prepareParentForShadow(vh.mGridView);
+        vh.getGridView().setFocusDrawingOrderEnabled(mShadowOverlayHelper.getShadowType()
+                == ShadowOverlayHelper.SHADOW_STATIC);
         FocusHighlightHelper.setupBrowseItemFocusHighlight(vh.mItemBridgeAdapter,
                 mFocusZoomFactor, mUseFocusDimmer);
 
@@ -286,6 +297,39 @@
         });
     }
 
+    /**
+     * Set if keeps foreground of child of this grid, the foreground will not
+     * be used for overlay color.  Default value is true.
+     *
+     * @param keep   True if keep foreground of child of this grid.
+     */
+    public final void setKeepChildForeground(boolean keep) {
+        mKeepChildForeground = keep;
+    }
+
+    /**
+     * Returns true if keeps foreground of child of this grid, the foreground will not
+     * be used for overlay color.  Default value is true.
+     *
+     * @return   True if keeps foreground of child of this grid.
+     */
+    public final boolean getKeepChildForeground() {
+        return mKeepChildForeground;
+    }
+
+    /**
+     * Create ShadowOverlayHelper Options.  Subclass may override.
+     * e.g.
+     * <code>
+     * return new ShadowOverlayHelper.Options().roundedCornerRadius(10);
+     * </code>
+     *
+     * @return   The options to be used for shadow, overlay and rouded corner.
+     */
+    protected ShadowOverlayHelper.Options createShadowOverlayOptions() {
+        return ShadowOverlayHelper.Options.DEFAULT;
+    }
+
     @Override
     public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
         if (DEBUG) Log.v(TAG, "onBindViewHolder " + item);
@@ -345,4 +389,18 @@
             }
         }
     }
+
+    /**
+     * Changes the visibility of views.  The entrance transition will be run against the views that
+     * change visibilities.  This method is called by the fragment, it should not be called
+     * directly by the application.
+     *
+     * @param holder         The ViewHolder for the vertical grid.
+     * @param afterEntrance  true if children of vertical grid participating in entrance transition
+     *                       should be set to visible, false otherwise.
+     */
+    public void setEntranceTransitionState(VerticalGridPresenter.ViewHolder holder,
+            boolean afterEntrance) {
+        holder.mGridView.setChildrenVisibility(afterEntrance? View.VISIBLE : View.INVISIBLE);
+    }
 }
diff --git a/v17/preference-leanback/Android.mk b/v17/preference-leanback/Android.mk
index c3bc803..14be7eb 100644
--- a/v17/preference-leanback/Android.mk
+++ b/v17/preference-leanback/Android.mk
@@ -34,6 +34,8 @@
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files := $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 #  A helper sub-library that makes direct use of API 21.
@@ -41,9 +43,12 @@
 LOCAL_MODULE := android-support-v17-preference-leanback-api21
 LOCAL_SDK_VERSION := 21
 LOCAL_SRC_FILES := $(call all-java-files-under, api21)
-LOCAL_JAVA_LIBRARIES := android-support-v17-preference-leanback-res
+LOCAL_JAVA_LIBRARIES := android-support-v17-preference-leanback-res \
+        android-support-v17-leanback
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # Here is the final static library that apps can link against.
 # The R class is automatically excluded from the generated library.
 # Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -65,11 +70,12 @@
         android-support-v17-preference-leanback-res
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # API Check
 # ---------------------------------------------
 support_module := $(LOCAL_MODULE)
 support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
 support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
 support_module_java_packages := android.support.v17.preference
 include $(SUPPORT_API_CHECK)
diff --git a/v17/preference-leanback/api/23.txt b/v17/preference-leanback/api/23.0.0.txt
similarity index 100%
rename from v17/preference-leanback/api/23.txt
rename to v17/preference-leanback/api/23.0.0.txt
diff --git a/v17/preference-leanback/api/23.txt b/v17/preference-leanback/api/23.1.0.txt
similarity index 100%
copy from v17/preference-leanback/api/23.txt
copy to v17/preference-leanback/api/23.1.0.txt
diff --git a/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java b/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
index 2002a54..37e7a79 100644
--- a/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
+++ b/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
@@ -16,21 +16,10 @@
 
 package android.support.v17.preference;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
+import android.support.v17.leanback.transition.FadeAndShortSlide;
 import android.app.Fragment;
-import android.graphics.Path;
-import android.transition.Fade;
 import android.transition.Transition;
-import android.transition.TransitionValues;
-import android.transition.Visibility;
 import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
 
 /**
  * @hide
@@ -38,8 +27,8 @@
 public class LeanbackPreferenceFragmentTransitionHelperApi21 {
 
     public static void addTransitions(Fragment f) {
-        final Transition transitionStartEdge = new FadeAndShortSlideTransition(Gravity.START);
-        final Transition transitionEndEdge = new FadeAndShortSlideTransition(Gravity.END);
+        final Transition transitionStartEdge = new FadeAndShortSlide(Gravity.START);
+        final Transition transitionEndEdge = new FadeAndShortSlide(Gravity.END);
 
         f.setEnterTransition(transitionEndEdge);
         f.setExitTransition(transitionStartEdge);
@@ -47,273 +36,5 @@
         f.setReturnTransition(transitionEndEdge);
     }
 
-    private static class FadeAndShortSlideTransition extends Visibility {
-
-        private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
-//        private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
-        private static final String PROPNAME_SCREEN_POSITION =
-                "android:fadeAndShortSlideTransition:screenPosition";
-
-        private CalculateSlide mSlideCalculator = sCalculateEnd;
-        private Visibility mFade = new Fade();
-
-        private interface CalculateSlide {
-
-            /** Returns the translation value for view when it goes out of the scene */
-            float getGoneX(ViewGroup sceneRoot, View view);
-        }
-
-        private static final CalculateSlide sCalculateStart = new CalculateSlide() {
-            @Override
-            public float getGoneX(ViewGroup sceneRoot, View view) {
-                final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-                final float x;
-                if (isRtl) {
-                    x = view.getTranslationX() + sceneRoot.getWidth() / 4;
-                } else {
-                    x = view.getTranslationX() - sceneRoot.getWidth() / 4;
-                }
-                return x;
-            }
-        };
-
-        private static final CalculateSlide sCalculateEnd = new CalculateSlide() {
-            @Override
-            public float getGoneX(ViewGroup sceneRoot, View view) {
-                final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-                final float x;
-                if (isRtl) {
-                    x = view.getTranslationX() - sceneRoot.getWidth() / 4;
-                } else {
-                    x = view.getTranslationX() + sceneRoot.getWidth() / 4;
-                }
-                return x;
-            }
-        };
-
-        public FadeAndShortSlideTransition(int slideEdge) {
-            setSlideEdge(slideEdge);
-        }
-
-        @Override
-        public void setEpicenterCallback(EpicenterCallback epicenterCallback) {
-            super.setEpicenterCallback(epicenterCallback);
-            mFade.setEpicenterCallback(epicenterCallback);
-        }
-
-        private void captureValues(TransitionValues transitionValues) {
-            View view = transitionValues.view;
-            int[] position = new int[2];
-            view.getLocationOnScreen(position);
-            transitionValues.values.put(PROPNAME_SCREEN_POSITION, position[0]);
-        }
-
-        @Override
-        public void captureStartValues(TransitionValues transitionValues) {
-            super.captureStartValues(transitionValues);
-            mFade.captureStartValues(transitionValues);
-            captureValues(transitionValues);
-        }
-
-        @Override
-        public void captureEndValues(TransitionValues transitionValues) {
-            super.captureEndValues(transitionValues);
-            mFade.captureEndValues(transitionValues);
-            captureValues(transitionValues);
-        }
-
-        public void setSlideEdge(int slideEdge) {
-            switch (slideEdge) {
-                case Gravity.START:
-                    mSlideCalculator = sCalculateStart;
-                    break;
-                case Gravity.END:
-                    mSlideCalculator = sCalculateEnd;
-                    break;
-                default:
-                    throw new IllegalArgumentException("Invalid slide direction");
-            }
-//            SidePropagation propagation = new SidePropagation();
-//            propagation.setSide(slideEdge);
-//            setPropagation(propagation);
-        }
-
-        @Override
-        public Animator onAppear(ViewGroup sceneRoot, View view,
-                TransitionValues startValues, TransitionValues endValues) {
-            if (endValues == null) {
-                return null;
-            }
-            Integer position = (Integer) endValues.values.get(PROPNAME_SCREEN_POSITION);
-            float endX = view.getTranslationX();
-            float startX = mSlideCalculator.getGoneX(sceneRoot, view);
-            final Animator slideAnimator = TranslationAnimationCreator
-                    .createAnimation(view, endValues, position,
-                            startX, endX, sDecelerate, this);
-            final AnimatorSet set = new AnimatorSet();
-            set.play(slideAnimator)
-                    .with(mFade.onAppear(sceneRoot, view, startValues, endValues));
-
-            return set;
-        }
-
-        @Override
-        public Animator onDisappear(ViewGroup sceneRoot, View view,
-                TransitionValues startValues, TransitionValues endValues) {
-            if (startValues == null) {
-                return null;
-            }
-            Integer position = (Integer) startValues.values.get(PROPNAME_SCREEN_POSITION);
-            float startX = view.getTranslationX();
-            float endX = mSlideCalculator.getGoneX(sceneRoot, view);
-            final Animator slideAnimator = TranslationAnimationCreator
-                    .createAnimation(view, startValues, position,
-                            startX, endX, sDecelerate /*sAccelerate*/, this);
-            final AnimatorSet set = new AnimatorSet();
-            set.play(slideAnimator)
-                    .with(mFade.onDisappear(sceneRoot, view, startValues, endValues));
-
-            return set;
-        }
-
-        @Override
-        public Transition addListener(TransitionListener listener) {
-            mFade.addListener(listener);
-            return super.addListener(listener);
-        }
-
-        @Override
-        public Transition removeListener(TransitionListener listener) {
-            mFade.removeListener(listener);
-            return super.removeListener(listener);
-        }
-
-        @Override
-        public Transition clone() {
-            FadeAndShortSlideTransition clone = null;
-            clone = (FadeAndShortSlideTransition) super.clone();
-            clone.mFade = (Visibility) mFade.clone();
-            return clone;
-        }
-    }
-
-    /**
-     * This class is used by Slide and Explode to create an animator that goes from the start
-     * position to the end position. It takes into account the canceled position so that it
-     * will not blink out or shift suddenly when the transition is interrupted.
-     */
-    private static class TranslationAnimationCreator {
-
-        /**
-         * Creates an animator that can be used for x and/or y translations. When interrupted,
-         * it sets a tag to keep track of the position so that it may be continued from position.
-         *
-         * @param view The view being moved. This may be in the overlay for onDisappear.
-         * @param values The values containing the view in the view hierarchy.
-         * @param viewPosX The x screen coordinate of view
-         * @param startX The start translation x of view
-         * @param endX The end translation x of view
-         * @param interpolator The interpolator to use with this animator.
-         * @return An animator that moves from (startX, startY) to (endX, endY) unless there was
-         * a previous interruption, in which case it moves from the current position to
-         * (endX, endY).
-         */
-        static Animator createAnimation(View view, TransitionValues values, int viewPosX,
-                float startX, float endX, TimeInterpolator interpolator,
-                Transition transition) {
-            float terminalX = view.getTranslationX();
-            Integer startPosition = (Integer) values.view.getTag(R.id.transitionPosition);
-            if (startPosition != null) {
-                startX = startPosition - viewPosX + terminalX;
-            }
-            // Initial position is at translation startX, startY, so position is offset by that
-            // amount
-            int startPosX = viewPosX + Math.round(startX - terminalX);
-
-            view.setTranslationX(startX);
-            if (startX == endX) {
-                return null;
-            }
-            Path path = new Path();
-            path.moveTo(startX, 0);
-            path.lineTo(endX, 0);
-            ObjectAnimator anim =
-                    ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y, path);
-
-            TransitionPositionListener listener = new TransitionPositionListener(view, values.view,
-                    startPosX, terminalX);
-            transition.addListener(listener);
-            anim.addListener(listener);
-            anim.addPauseListener(listener);
-            anim.setInterpolator(interpolator);
-            return anim;
-        }
-
-        private static class TransitionPositionListener extends AnimatorListenerAdapter implements
-                Transition.TransitionListener {
-
-            private final View mViewInHierarchy;
-            private final View mMovingView;
-            private final int mStartX;
-            private Integer mTransitionPosition;
-            private float mPausedX;
-            private final float mTerminalX;
-
-            private TransitionPositionListener(View movingView, View viewInHierarchy,
-                    int startX, float terminalX) {
-                mMovingView = movingView;
-                mViewInHierarchy = viewInHierarchy;
-                mStartX = startX - Math.round(mMovingView.getTranslationX());
-                mTerminalX = terminalX;
-                mTransitionPosition = (Integer) mViewInHierarchy.getTag(R.id.transitionPosition);
-                if (mTransitionPosition != null) {
-                    mViewInHierarchy.setTag(R.id.transitionPosition, null);
-                }
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mTransitionPosition = Math.round(mStartX + mMovingView.getTranslationX());
-                mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition);
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animator) {
-            }
-
-            @Override
-            public void onAnimationPause(Animator animator) {
-                mPausedX = mMovingView.getTranslationX();
-                mMovingView.setTranslationX(mTerminalX);
-            }
-
-            @Override
-            public void onAnimationResume(Animator animator) {
-                mMovingView.setTranslationX(mPausedX);
-            }
-
-            @Override
-            public void onTransitionStart(Transition transition) {
-            }
-
-            @Override
-            public void onTransitionEnd(Transition transition) {
-                mMovingView.setTranslationX(mTerminalX);
-            }
-
-            @Override
-            public void onTransitionCancel(Transition transition) {
-            }
-
-            @Override
-            public void onTransitionPause(Transition transition) {
-            }
-
-            @Override
-            public void onTransitionResume(Transition transition) {
-            }
-        }
-
-    }
 
 }
diff --git a/v17/preference-leanback/build.gradle b/v17/preference-leanback/build.gradle
index 4063122..0ddcdd2 100644
--- a/v17/preference-leanback/build.gradle
+++ b/v17/preference-leanback/build.gradle
@@ -56,3 +56,37 @@
         abortOnError false
     }
 }
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri(rootProject.ext.supportRepoOut)) {
+            }
+
+            pom.project {
+                name 'Android Support Leanback Preference v17'
+                description "Android Support Leanback Preference v17"
+                url 'http://developer.android.com/tools/extras/support-library.html'
+                inceptionYear '2015'
+
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                        distribution 'repo'
+                    }
+                }
+
+                scm {
+                    url "http://source.android.com"
+                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+                }
+                developers {
+                    developer {
+                        name 'The Android Open Source Project'
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/v17/preference-leanback/res/values/ids.xml b/v17/preference-leanback/res/color/lb_preference_item_primary_text_color.xml
similarity index 70%
copy from v17/preference-leanback/res/values/ids.xml
copy to v17/preference-leanback/res/color/lb_preference_item_primary_text_color.xml
index 20c1eda..efdf1c0 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v17/preference-leanback/res/color/lb_preference_item_primary_text_color.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License
   -->
 
-<resources>
-    <item name="transitionPosition" type="id" />
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/lb_preference_item_primary_text_color_disabled" />
+    <item android:color="@color/lb_preference_item_primary_text_color_default"/>
+</selector>
diff --git a/v17/preference-leanback/res/values/ids.xml b/v17/preference-leanback/res/color/lb_preference_item_secondary_text_color.xml
similarity index 70%
copy from v17/preference-leanback/res/values/ids.xml
copy to v17/preference-leanback/res/color/lb_preference_item_secondary_text_color.xml
index 20c1eda..68bb81a 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v17/preference-leanback/res/color/lb_preference_item_secondary_text_color.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License
   -->
 
-<resources>
-    <item name="transitionPosition" type="id" />
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/lb_preference_item_secondary_text_color_disabled" />
+    <item android:color="@color/lb_preference_item_secondary_text_color_default"/>
+</selector>
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
index 9fae0f8..f073f3e 100644
--- a/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
@@ -20,6 +20,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/lb_preference_decor_list_background"
+    android:elevation="@dimen/lb_preference_decor_elevation"
     android:orientation="vertical"
     android:transitionGroup="false"
     >
@@ -29,17 +30,18 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="?attr/defaultBrandColor"
+        android:elevation="@dimen/lb_preference_decor_title_container_elevation"
         android:transitionGroup="false"
         >
         <TextView
             android:id="@+id/decor_title"
             android:layout_width="match_parent"
             android:layout_height="@dimen/lb_preference_decor_title_text_height"
+            android:layout_marginTop="@dimen/lb_preference_decor_title_margin_top"
+            android:layout_marginStart="@dimen/lb_preference_decor_title_margin_start"
+            android:layout_marginEnd="@dimen/lb_preference_decor_title_margin_end"
             android:fontFamily="sans-serif-condensed"
             android:gravity="center_vertical"
-            android:paddingTop="@dimen/lb_preference_decor_title_padding_top"
-            android:paddingStart="@dimen/lb_preference_decor_title_padding_start"
-            android:paddingEnd="@dimen/lb_preference_decor_title_padding_end"
             android:singleLine="true"
             android:textSize="@dimen/lb_preference_decor_title_text_size"
             android:textColor="?android:attr/textColorPrimary"
@@ -50,6 +52,7 @@
         android:id="@android:id/message"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:fontFamily="sans-serif-condensed"
         android:paddingTop="14dp"
         android:paddingBottom="14dp"
         android:paddingStart="24dp"
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml b/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
index 3b1345c..728ecff 100644
--- a/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
@@ -18,20 +18,35 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/container"
     android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:layout_height="wrap_content"
     android:background="?android:attr/selectableItemBackground"
     android:clickable="true"
     android:focusable="true"
     android:descendantFocusability="blocksDescendants"
-    android:orientation="horizontal">
+    android:orientation="horizontal"
+    android:paddingStart="@dimen/lb_preference_item_padding_start"
+    android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
     <CheckBox
         android:id="@+id/button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:gravity="center_vertical" />
+        android:layout_width="@dimen/lb_preference_item_icon_size"
+        android:layout_height="@dimen/lb_preference_item_icon_size"
+        android:layout_marginEnd="@dimen/lb_preference_item_icon_margin_end"
+        android:layout_gravity="center_vertical" />
+
+    <LinearLayout android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+            android:fontFamily="sans-serif-condensed"
+            android:textColor="@color/lb_preference_item_primary_text_color"
+            android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+    </LinearLayout>
+
 </LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml b/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
index eaf42a4..354ca41 100644
--- a/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
@@ -18,20 +18,35 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/container"
     android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:layout_height="wrap_content"
     android:background="?android:attr/selectableItemBackground"
     android:clickable="true"
     android:focusable="true"
     android:descendantFocusability="blocksDescendants"
-    android:orientation="horizontal">
+    android:orientation="horizontal"
+    android:paddingStart="@dimen/lb_preference_item_padding_start"
+    android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
     <RadioButton
         android:id="@+id/button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:gravity="center_vertical" />
+        android:layout_width="@dimen/lb_preference_item_icon_size"
+        android:layout_height="@dimen/lb_preference_item_icon_size"
+        android:layout_marginEnd="@dimen/lb_preference_item_icon_margin_end"
+        android:layout_gravity="center_vertical" />
+
+    <LinearLayout android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+            android:fontFamily="sans-serif-condensed"
+            android:textColor="@color/lb_preference_item_primary_text_color"
+            android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+    </LinearLayout>
+
 </LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference.xml b/v17/preference-leanback/res/layout/leanback_preference.xml
new file mode 100644
index 0000000..05ca21c
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preference.xml
@@ -0,0 +1,74 @@
+<?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/container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:clickable="true"
+    android:focusable="true"
+    android:descendantFocusability="blocksDescendants"
+    android:orientation="horizontal"
+    android:paddingStart="@dimen/lb_preference_item_padding_start"
+    android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
+    <FrameLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical" >
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/lb_preference_item_icon_size"
+            android:layout_height="@dimen/lb_preference_item_icon_size"
+            android:layout_marginEnd="@dimen/lb_preference_item_icon_margin_end"
+            />
+    </FrameLayout>
+
+    <LinearLayout android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical">
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+            android:fontFamily="sans-serif-condensed"
+            android:textColor="@color/lb_preference_item_primary_text_color"
+            android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif-condensed"
+            android:textColor="@color/lb_preference_item_secondary_text_color"
+            android:textSize="@dimen/lb_preference_item_secondary_text_size"
+            android:maxLines="4" />
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+    </LinearLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference_category.xml b/v17/preference-leanback/res/layout/leanback_preference_category.xml
new file mode 100644
index 0000000..9b978f3
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preference_category.xml
@@ -0,0 +1,33 @@
+<?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
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/lb_preference_category_height"
+    android:clipToPadding="false"
+    android:paddingStart="@dimen/lb_preference_item_padding_start"
+    android:paddingEnd="@dimen/lb_preference_item_padding_end">
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:fontFamily="sans-serif-condensed"
+        android:textColor="?android:attr/colorAccent"
+        android:textSize="@dimen/lb_preference_category_text_size"/>
+</FrameLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference_fragment.xml b/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
index d119c2d..199e0f7 100644
--- a/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
+++ b/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
@@ -20,6 +20,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/lb_preference_decor_list_background"
+    android:elevation="@dimen/lb_preference_decor_elevation"
     android:orientation="vertical"
     android:transitionGroup="false"
     >
@@ -29,17 +30,18 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="?attr/defaultBrandColor"
+        android:elevation="@dimen/lb_preference_decor_title_container_elevation"
         android:transitionGroup="false"
         >
         <TextView
             android:id="@+id/decor_title"
             android:layout_width="match_parent"
             android:layout_height="@dimen/lb_preference_decor_title_text_height"
+            android:layout_marginTop="@dimen/lb_preference_decor_title_margin_top"
+            android:layout_marginStart="@dimen/lb_preference_decor_title_margin_start"
+            android:layout_marginEnd="@dimen/lb_preference_decor_title_margin_end"
             android:fontFamily="sans-serif-condensed"
             android:gravity="center_vertical"
-            android:paddingTop="@dimen/lb_preference_decor_title_padding_top"
-            android:paddingStart="@dimen/lb_preference_decor_title_padding_start"
-            android:paddingEnd="@dimen/lb_preference_decor_title_padding_end"
             android:singleLine="true"
             android:textSize="@dimen/lb_preference_decor_title_text_size"
             android:textColor="?android:attr/textColorPrimary"
diff --git a/v17/preference-leanback/res/layout/leanback_preference_information.xml b/v17/preference-leanback/res/layout/leanback_preference_information.xml
new file mode 100644
index 0000000..18da8d9
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preference_information.xml
@@ -0,0 +1,61 @@
+<?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/container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:clickable="false"
+    android:focusable="false"
+    android:descendantFocusability="blocksDescendants"
+    android:orientation="horizontal"
+    android:paddingStart="@dimen/lb_preference_item_padding_start"
+    android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
+    <LinearLayout android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical">
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+            android:fontFamily="sans-serif-condensed"
+            android:textColor="@color/lb_preference_item_primary_text_color"
+            android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif-condensed"
+            android:textColor="@color/lb_preference_item_secondary_text_color"
+            android:textSize="@dimen/lb_preference_item_secondary_text_size"
+            android:maxLines="4" />
+        <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+    </LinearLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preferences_list.xml b/v17/preference-leanback/res/layout/leanback_preferences_list.xml
index 15ecebc..21e4e4a 100644
--- a/v17/preference-leanback/res/layout/leanback_preferences_list.xml
+++ b/v17/preference-leanback/res/layout/leanback_preferences_list.xml
@@ -19,4 +19,5 @@
     android:id="@+id/list"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent" />
+    android:layout_height="match_parent"
+    style="?attr/preferenceFragmentListStyle" />
diff --git a/v17/preference-leanback/res/values/colors.xml b/v17/preference-leanback/res/values/colors.xml
index de6c888..30a373a 100644
--- a/v17/preference-leanback/res/values/colors.xml
+++ b/v17/preference-leanback/res/values/colors.xml
@@ -16,4 +16,11 @@
   -->
 <resources>
     <color name="lb_preference_decor_list_background">#263238</color>
+
+    <color name="lb_preference_item_primary_text_color_default">#EEEEEE</color>
+    <color name="lb_preference_item_primary_text_color_disabled">#4DEEEEEE</color>
+
+    <color name="lb_preference_item_secondary_text_color_default">#B3EEEEEE</color>
+    <color name="lb_preference_item_secondary_text_color_disabled">#4DEEEEEE</color>
+
 </resources>
diff --git a/v17/preference-leanback/res/values/dimens.xml b/v17/preference-leanback/res/values/dimens.xml
index 49763fe..f3d36af 100644
--- a/v17/preference-leanback/res/values/dimens.xml
+++ b/v17/preference-leanback/res/values/dimens.xml
@@ -15,11 +15,27 @@
   ~ limitations under the License
   -->
 <resources>
-  <dimen name="lb_preference_decor_title_text_height">64dp</dimen>
-  <dimen name="lb_preference_decor_title_padding_top">27dp</dimen>
-  <dimen name="lb_preference_decor_title_padding_start">24dp</dimen>
-  <dimen name="lb_preference_decor_title_padding_end">56dp</dimen>
-  <dimen name="lb_preference_decor_title_text_size">20sp</dimen>
+    <dimen name="lb_preference_decor_title_text_height">64dp</dimen>
+    <dimen name="lb_preference_decor_title_margin_top">27dp</dimen>
+    <dimen name="lb_preference_decor_title_margin_start">24dp</dimen>
+    <dimen name="lb_preference_decor_title_margin_end">56dp</dimen>
+    <dimen name="lb_preference_decor_title_text_size">20sp</dimen>
+    <dimen name="lb_preference_decor_title_container_elevation">2dp</dimen>
+    <dimen name="lb_preference_decor_elevation">6dp</dimen>
 
-  <dimen name="lb_settings_pane_width">360dp</dimen>
+    <dimen name="lb_preference_item_padding_start">24dp</dimen>
+    <dimen name="lb_preference_item_padding_end">56dp</dimen>
+    <dimen name="lb_preference_item_icon_size">32dp</dimen>
+    <dimen name="lb_preference_item_icon_margin_end">16dp</dimen>
+
+    <dimen name="lb_preference_item_primary_text_size">14sp</dimen>
+    <dimen name="lb_preference_item_primary_text_margin_bottom">2dp</dimen>
+    <dimen name="lb_preference_item_secondary_text_size">12sp</dimen>
+    <dimen name="lb_preference_item_text_space_top">14dp</dimen>
+    <dimen name="lb_preference_item_text_space_bottom">13dp</dimen>
+
+    <dimen name="lb_preference_category_text_size">12sp</dimen>
+    <dimen name="lb_preference_category_height">40dp</dimen>
+
+    <dimen name="lb_settings_pane_width">360dp</dimen>
 </resources>
diff --git a/v17/preference-leanback/res/values/styles.xml b/v17/preference-leanback/res/values/styles.xml
new file mode 100644
index 0000000..42d2b5b
--- /dev/null
+++ b/v17/preference-leanback/res/values/styles.xml
@@ -0,0 +1,74 @@
+<?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
+  -->
+
+<resources>
+
+    <style name="LeanbackPreference">
+        <item name="android:layout">@layout/leanback_preference</item>
+    </style>
+
+    <style name="LeanbackPreference.Information">
+        <item name="android:layout">@layout/leanback_preference_information</item>
+        <item name="android:enabled">false</item>
+        <item name="android:shouldDisableView">false</item>
+    </style>
+
+    <style name="LeanbackPreference.Category">
+        <item name="android:layout">@layout/leanback_preference_category</item>
+        <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
+        <item name="android:shouldDisableView">false</item>
+        <item name="android:selectable">false</item>
+    </style>
+
+    <style name="LeanbackPreference.CheckBoxPreference">
+        <item name="android:widgetLayout">@layout/preference_widget_checkbox</item>
+    </style>
+
+    <style name="LeanbackPreference.SwitchPreferenceCompat">
+        <item name="android:widgetLayout">@layout/preference_widget_switch_compat</item>
+        <item name="android:switchTextOn">@string/v7_preference_on</item>
+        <item name="android:switchTextOff">@string/v7_preference_off</item>
+    </style>
+
+    <style name="LeanbackPreference.SwitchPreference">
+        <item name="android:widgetLayout">@layout/preference_widget_switch</item>
+        <item name="android:switchTextOn">@string/v7_preference_on</item>
+        <item name="android:switchTextOff">@string/v7_preference_off</item>
+    </style>
+
+    <style name="LeanbackPreference.PreferenceScreen">
+    </style>
+
+    <style name="LeanbackPreference.DialogPreference">
+        <item name="android:positiveButtonText">@android:string/ok</item>
+        <item name="android:negativeButtonText">@android:string/cancel</item>
+    </style>
+
+    <style name="LeanbackPreference.DialogPreference.EditTextPreference">
+        <item name="android:dialogLayout">@layout/preference_dialog_edittext</item>
+    </style>
+
+    <style name="PreferenceFragment.Leanback">
+        <item name="android:divider">@null</item>
+    </style>
+
+    <style name="PreferenceFragmentList.Leanback">
+        <item name="android:paddingStart">0dp</item>
+        <item name="android:paddingEnd">0dp</item>
+    </style>
+
+</resources>
diff --git a/v17/preference-leanback/res/values/themes.xml b/v17/preference-leanback/res/values/themes.xml
new file mode 100644
index 0000000..591fdfa
--- /dev/null
+++ b/v17/preference-leanback/res/values/themes.xml
@@ -0,0 +1,33 @@
+<?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
+  -->
+
+<resources>
+    <style name="PreferenceThemeOverlay.v14.Leanback">
+        <item name="preferenceScreenStyle">@style/LeanbackPreference.PreferenceScreen</item>
+        <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment.Leanback</item>
+        <item name="preferenceFragmentStyle">@style/PreferenceFragment.Leanback</item>
+        <item name="preferenceCategoryStyle">@style/LeanbackPreference.Category</item>
+        <item name="preferenceStyle">@style/LeanbackPreference</item>
+        <item name="preferenceInformationStyle">@style/LeanbackPreference.Information</item>
+        <item name="checkBoxPreferenceStyle">@style/LeanbackPreference.CheckBoxPreference</item>
+        <item name="switchPreferenceCompatStyle">@style/LeanbackPreference.SwitchPreferenceCompat</item>
+        <item name="switchPreferenceStyle">@style/LeanbackPreference.SwitchPreference</item>
+        <item name="dialogPreferenceStyle">@style/LeanbackPreference.DialogPreference</item>
+        <item name="editTextPreferenceStyle">@style/LeanbackPreference.DialogPreference.EditTextPreference</item>
+        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Leanback</item>
+    </style>
+</resources>
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
index 92fdd62..a82f543 100644
--- a/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
@@ -156,8 +156,15 @@
         public void onItemClick(ViewHolder viewHolder) {
             final int index = viewHolder.getAdapterPosition();
             final CharSequence entry = mEntryValues[index];
-            mSelectedValue = entry;
-            ((ListPreference) getPreference()).setValue(entry.toString());
+            final ListPreference preference = (ListPreference) getPreference();
+            if (index >= 0) {
+                String value = mEntryValues[index].toString();
+                if (preference.callChangeListener(value)) {
+                    preference.setValue(value);
+                    mSelectedValue = entry;
+                }
+            }
+
             getFragmentManager().popBackStack();
             notifyDataSetChanged();
         }
@@ -206,7 +213,20 @@
             } else {
                 mSelections.add(entry);
             }
-            ((MultiSelectListPreference) getPreference()).setValues(mSelections);
+            final MultiSelectListPreference multiSelectListPreference
+                    = (MultiSelectListPreference) getPreference();
+            // Pass copies of the set to callChangeListener and setValues to avoid mutations
+            if (multiSelectListPreference.callChangeListener(new HashSet<>(mSelections))) {
+                multiSelectListPreference.setValues(new HashSet<>(mSelections));
+            } else {
+                // Change refused, back it out
+                if (mSelections.contains(entry)) {
+                    mSelections.remove(entry);
+                } else {
+                    mSelections.add(entry);
+                }
+            }
+
             notifyDataSetChanged();
         }
     }
diff --git a/v17/tests/AndroidManifest.xml b/v17/tests/AndroidManifest.xml
index f78d435..f4dd293 100644
--- a/v17/tests/AndroidManifest.xml
+++ b/v17/tests/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v17.leanback.tests">
-    <uses-sdk android:minSdkVersion="17"  android:targetSdkVersion="17"/>
+    <uses-sdk android:minSdkVersion="17"  android:targetSdkVersion="23"/>
 
     <!--
         This declares that this application uses the instrumentation test runner targeting
@@ -33,6 +33,14 @@
         <activity android:name="android.support.v17.leanback.widget.GridActivity"
             android:exported="true" />
 
-    </application>
+        <activity android:name="android.support.v17.leanback.app.BrowseFragmentTestActivity"
+            android:theme="@style/Theme.Leanback.Browse"
+            android:exported="true" />
+
+        <activity android:name="android.support.v17.leanback.app.BrowseSupportFragmentTestActivity"
+            android:theme="@style/Theme.Leanback.Browse"
+            android:exported="true" />
+
+        </application>
 
 </manifest>
diff --git a/v17/tests/generatev4.py b/v17/tests/generatev4.py
new file mode 100755
index 0000000..8dc4dc2
--- /dev/null
+++ b/v17/tests/generatev4.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+
+# 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.
+
+import os
+import sys
+
+print "Generate v4 fragment related code for leanback"
+
+files = ['BrowseTest']
+
+cls = ['BrowseTest', 'Background', 'Base', 'BaseRow', 'Browse', 'Details', 'Error', 'Headers',
+      'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded']
+
+for w in files:
+    print "copy {}Fragment to {}SupportFragment".format(w, w)
+
+    file = open('src/android/support/v17/leanback/app/{}Fragment.java'.format(w), 'r')
+    outfile = open('src/android/support/v17/leanback/app/{}SupportFragment.java'.format(w), 'w')
+
+    outfile.write("/* This file is auto-generated from {}Fragment.java.  DO NOT MODIFY. */\n\n".format(w))
+
+    for line in file:
+        for w in cls:
+            line = line.replace('{}Fragment'.format(w), '{}SupportFragment'.format(w))
+        line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
+        line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+        outfile.write(line)
+    file.close()
+    outfile.close()
+
+testcls = ['Browse']
+
+for w in testcls:
+    print "copy {}FrgamentTest to {}SupportFragmentTest".format(w, w)
+
+    file = open('src/android/support/v17/leanback/app/{}FragmentTest.java'.format(w), 'r')
+    outfile = open('src/android/support/v17/leanback/app/{}SupportFragmentTest.java'.format(w), 'w')
+
+    outfile.write("/* This file is auto-generated from {}FrgamentTest.java.  DO NOT MODIFY. */\n\n".format(w))
+
+    for line in file:
+        for w in testcls:
+            line = line.replace('{}FragmentTest'.format(w), '{}SupportFragmentTest'.format(w))
+            line = line.replace('{}FragmentTestActivity'.format(w), '{}SupportFragmentTestActivity'.format(w))
+            line = line.replace('{}TestFragment'.format(w), '{}TestSupportFragment'.format(w))
+        outfile.write(line)
+    file.close()
+    outfile.close()
+
+
+print "copy BrowseFragmentTestActivity to BrowseSupportFragmentTestActivity"
+file = open('src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java', 'r')
+outfile = open('src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java', 'w')
+outfile.write("/* This file is auto-generated from BrowseFragmentTestActivity.java.  DO NOT MODIFY. */\n\n")
+for line in file:
+    line = line.replace('BrowseTestFragment', 'BrowseTestSupportFragment')
+    line = line.replace('BrowseFragmentTestActivity', 'BrowseSupportFragmentTestActivity')
+    line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
+    line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+    line = line.replace('extends Activity', 'extends FragmentActivity')
+    line = line.replace('getFragmentManager', 'getSupportFragmentManager')
+    outfile.write(line)
+file.close()
+outfile.close()
+
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml b/v17/tests/res/layout/browse.xml
similarity index 61%
copy from v17/leanback/res/animator/lb_guidedactions_item_checked.xml
copy to v17/tests/res/layout/browse.xml
index 463b9f7..01226da 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml
+++ b/v17/tests/res/layout/browse.xml
@@ -14,9 +14,15 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="@integer/lb_guidedactions_item_animation_duration"
-    android:propertyName="alpha"
-    android:valueFrom="0.0"
-    android:valueTo="1.0"
-    android:valueType="floatType" />
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/main_frame"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+  <!-- container for hosting GuidedStepFragment background -->
+  <FrameLayout android:id="@+id/lb_guidedstep_background"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
+
+</FrameLayout>
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTest.java b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTest.java
new file mode 100644
index 0000000..e9b1063
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.support.v17.leanback.tests.R;
+import android.test.ActivityInstrumentationTestCase2;
+import android.text.Selection;
+import android.text.Spannable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseFragmentTest extends
+        ActivityInstrumentationTestCase2<BrowseFragmentTestActivity> {
+
+    static final long TRANSITION_LENGTH = 1000;
+
+    Instrumentation mInstrumentation;
+    BrowseFragmentTestActivity mActivity;
+
+    public BrowseFragmentTest() {
+        super(BrowseFragmentTestActivity.class);
+    }
+
+    private void initActivity(Intent intent) {
+        setActivityIntent(intent);
+        mActivity = getActivity();
+        try {
+        Thread.sleep(intent.getLongExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY,
+                BrowseTestFragment.DEFAULT_LOAD_DATA_DELAY) + TRANSITION_LENGTH);
+        } catch (InterruptedException ex) {
+        }
+    }
+
+    public void testTwoBackKeysWithBackStack() throws Throwable {
+        mInstrumentation = getInstrumentation();
+        Intent intent = new Intent(mInstrumentation.getContext(), BrowseFragmentTestActivity.class);
+        intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+        intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
+        initActivity(intent);
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        Thread.sleep(TRANSITION_LENGTH);
+
+        sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+    }
+
+    public void testTwoBackKeysWithoutBackStack() throws Throwable {
+        mInstrumentation = getInstrumentation();
+        Intent intent = new Intent(mInstrumentation.getContext(), BrowseFragmentTestActivity.class);
+        intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+        intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
+        initActivity(intent);
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        Thread.sleep(TRANSITION_LENGTH);
+
+        sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+    }
+
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
new file mode 100644
index 0000000..ee433bd
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.app.FragmentTransaction;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.tests.R;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseFragmentTestActivity extends Activity {
+
+    public static final String EXTRA_ADD_TO_BACKSTACK = "addToBackStack";
+    public static final String EXTRA_NUM_ROWS = "numRows";
+    public static final String EXTRA_REPEAT_PER_ROW = "repeatPerRow";
+    public static final String EXTRA_LOAD_DATA_DELAY = "loadDataDelay";
+    public static final String EXTRA_TEST_ENTRANCE_TRANSITION = "testEntranceTransition";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+
+        BrowseTestFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
+                BrowseTestFragment.DEFAULT_NUM_ROWS);
+        BrowseTestFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
+                BrowseTestFragment.DEFAULT_REPEAT_PER_ROW);
+        BrowseTestFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
+                BrowseTestFragment.DEFAULT_LOAD_DATA_DELAY);
+        BrowseTestFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
+                EXTRA_TEST_ENTRANCE_TRANSITION,
+                BrowseTestFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
+        setContentView(R.layout.browse);
+        FragmentTransaction ft = getFragmentManager().beginTransaction();
+        ft.replace(R.id.main_frame, new BrowseTestFragment());
+        if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+            ft.addToBackStack(null);
+        }
+        ft.commit();
+    }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
new file mode 100644
index 0000000..0c901be
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
@@ -0,0 +1,95 @@
+/* This file is auto-generated from BrowseFrgamentTest.java.  DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.support.v17.leanback.tests.R;
+import android.test.ActivityInstrumentationTestCase2;
+import android.text.Selection;
+import android.text.Spannable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseSupportFragmentTest extends
+        ActivityInstrumentationTestCase2<BrowseSupportFragmentTestActivity> {
+
+    static final long TRANSITION_LENGTH = 1000;
+
+    Instrumentation mInstrumentation;
+    BrowseSupportFragmentTestActivity mActivity;
+
+    public BrowseSupportFragmentTest() {
+        super(BrowseSupportFragmentTestActivity.class);
+    }
+
+    private void initActivity(Intent intent) {
+        setActivityIntent(intent);
+        mActivity = getActivity();
+        try {
+        Thread.sleep(intent.getLongExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY,
+                BrowseTestSupportFragment.DEFAULT_LOAD_DATA_DELAY) + TRANSITION_LENGTH);
+        } catch (InterruptedException ex) {
+        }
+    }
+
+    public void testTwoBackKeysWithBackStack() throws Throwable {
+        mInstrumentation = getInstrumentation();
+        Intent intent = new Intent(mInstrumentation.getContext(), BrowseSupportFragmentTestActivity.class);
+        intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+        intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
+        initActivity(intent);
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        Thread.sleep(TRANSITION_LENGTH);
+
+        sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+    }
+
+    public void testTwoBackKeysWithoutBackStack() throws Throwable {
+        mInstrumentation = getInstrumentation();
+        Intent intent = new Intent(mInstrumentation.getContext(), BrowseSupportFragmentTestActivity.class);
+        intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+        intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
+        initActivity(intent);
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        Thread.sleep(TRANSITION_LENGTH);
+
+        sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+    }
+
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
new file mode 100644
index 0000000..036d254
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
@@ -0,0 +1,60 @@
+/* This file is auto-generated from BrowseFragmentTestActivity.java.  DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.tests.R;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseSupportFragmentTestActivity extends FragmentActivity {
+
+    public static final String EXTRA_ADD_TO_BACKSTACK = "addToBackStack";
+    public static final String EXTRA_NUM_ROWS = "numRows";
+    public static final String EXTRA_REPEAT_PER_ROW = "repeatPerRow";
+    public static final String EXTRA_LOAD_DATA_DELAY = "loadDataDelay";
+    public static final String EXTRA_TEST_ENTRANCE_TRANSITION = "testEntranceTransition";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+
+        BrowseTestSupportFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
+                BrowseTestSupportFragment.DEFAULT_NUM_ROWS);
+        BrowseTestSupportFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
+                BrowseTestSupportFragment.DEFAULT_REPEAT_PER_ROW);
+        BrowseTestSupportFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
+                BrowseTestSupportFragment.DEFAULT_LOAD_DATA_DELAY);
+        BrowseTestSupportFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
+                EXTRA_TEST_ENTRANCE_TRANSITION,
+                BrowseTestSupportFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
+        setContentView(R.layout.browse);
+        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+        ft.replace(R.id.main_frame, new BrowseTestSupportFragment());
+        if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+            ft.addToBackStack(null);
+        }
+        ft.commit();
+    }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseTestFragment.java b/v17/tests/src/android/support/v17/leanback/app/BrowseTestFragment.java
new file mode 100644
index 0000000..744a926
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseTestFragment.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseTestFragment extends BrowseFragment {
+    private static final String TAG = "BrowseTestFragment";
+
+    final static int DEFAULT_NUM_ROWS = 100;
+    final static int DEFAULT_REPEAT_PER_ROW = 20;
+    final static long DEFAULT_LOAD_DATA_DELAY = 2000;
+    final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
+
+    static int NUM_ROWS = DEFAULT_NUM_ROWS;
+    static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
+    static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
+    static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
+
+    private ArrayObjectAdapter mRowsAdapter;
+
+    // For good performance, it's important to use a single instance of
+    // a card presenter for all rows using that presenter.
+    final static StringPresenter sCardPresenter = new StringPresenter();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+
+        setTitle("BrowseTestFragment");
+        setHeadersState(HEADERS_ENABLED);
+
+        setOnSearchClickedListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                Log.i(TAG, "onSearchClicked");
+            }
+        });
+
+        setupRows();
+        setOnItemViewClickedListener(new ItemViewClickedListener());
+        setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
+            @Override
+            public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                    RowPresenter.ViewHolder rowViewHolder, Row row) {
+                Log.i(TAG, "onItemSelected: " + item + " row " + row);
+            }
+        });
+        if (TEST_ENTRANCE_TRANSITION) {
+            // don't run entrance transition if fragment is restored.
+            if (savedInstanceState == null) {
+                prepareEntranceTransition();
+            }
+        }
+        // simulates in a real world use case  data being loaded two seconds later
+        new Handler().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                loadData();
+                startEntranceTransition();
+            }
+        }, LOAD_DATA_DELAY);
+    }
+
+    private void setupRows() {
+        ListRowPresenter lrp = new ListRowPresenter();
+
+        mRowsAdapter = new ArrayObjectAdapter(lrp);
+
+        setAdapter(mRowsAdapter);
+    }
+
+    private void loadData() {
+        for (int i = 0; i < NUM_ROWS; ++i) {
+            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(sCardPresenter);
+            for (int j = 0; j < REPEAT_PER_ROW; ++j) {
+                listRowAdapter.add("Hello world");
+                listRowAdapter.add("This is a test");
+                listRowAdapter.add("Android TV");
+                listRowAdapter.add("Leanback");
+                listRowAdapter.add("Hello world");
+                listRowAdapter.add("Android TV");
+                listRowAdapter.add("Leanback");
+                listRowAdapter.add("GuidedStepFragment");
+            }
+            HeaderItem header = new HeaderItem(i, "Row " + i);
+            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+        }
+
+    }
+
+    private final class ItemViewClickedListener implements OnItemViewClickedListener {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                RowPresenter.ViewHolder rowViewHolder, Row row) {
+            Log.i(TAG, "onItemClicked: " + item + " row " + row);
+        }
+    }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseTestSupportFragment.java b/v17/tests/src/android/support/v17/leanback/app/BrowseTestSupportFragment.java
new file mode 100644
index 0000000..1a01b7b
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseTestSupportFragment.java
@@ -0,0 +1,128 @@
+/* This file is auto-generated from BrowseTestFragment.java.  DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseTestSupportFragment extends BrowseSupportFragment {
+    private static final String TAG = "BrowseTestSupportFragment";
+
+    final static int DEFAULT_NUM_ROWS = 100;
+    final static int DEFAULT_REPEAT_PER_ROW = 20;
+    final static long DEFAULT_LOAD_DATA_DELAY = 2000;
+    final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
+
+    static int NUM_ROWS = DEFAULT_NUM_ROWS;
+    static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
+    static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
+    static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
+
+    private ArrayObjectAdapter mRowsAdapter;
+
+    // For good performance, it's important to use a single instance of
+    // a card presenter for all rows using that presenter.
+    final static StringPresenter sCardPresenter = new StringPresenter();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+
+        setTitle("BrowseTestSupportFragment");
+        setHeadersState(HEADERS_ENABLED);
+
+        setOnSearchClickedListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                Log.i(TAG, "onSearchClicked");
+            }
+        });
+
+        setupRows();
+        setOnItemViewClickedListener(new ItemViewClickedListener());
+        setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
+            @Override
+            public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                    RowPresenter.ViewHolder rowViewHolder, Row row) {
+                Log.i(TAG, "onItemSelected: " + item + " row " + row);
+            }
+        });
+        if (TEST_ENTRANCE_TRANSITION) {
+            // don't run entrance transition if fragment is restored.
+            if (savedInstanceState == null) {
+                prepareEntranceTransition();
+            }
+        }
+        // simulates in a real world use case  data being loaded two seconds later
+        new Handler().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                loadData();
+                startEntranceTransition();
+            }
+        }, LOAD_DATA_DELAY);
+    }
+
+    private void setupRows() {
+        ListRowPresenter lrp = new ListRowPresenter();
+
+        mRowsAdapter = new ArrayObjectAdapter(lrp);
+
+        setAdapter(mRowsAdapter);
+    }
+
+    private void loadData() {
+        for (int i = 0; i < NUM_ROWS; ++i) {
+            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(sCardPresenter);
+            for (int j = 0; j < REPEAT_PER_ROW; ++j) {
+                listRowAdapter.add("Hello world");
+                listRowAdapter.add("This is a test");
+                listRowAdapter.add("Android TV");
+                listRowAdapter.add("Leanback");
+                listRowAdapter.add("Hello world");
+                listRowAdapter.add("Android TV");
+                listRowAdapter.add("Leanback");
+                listRowAdapter.add("GuidedStepFragment");
+            }
+            HeaderItem header = new HeaderItem(i, "Row " + i);
+            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+        }
+
+    }
+
+    private final class ItemViewClickedListener implements OnItemViewClickedListener {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                RowPresenter.ViewHolder rowViewHolder, Row row) {
+            Log.i(TAG, "onItemClicked: " + item + " row " + row);
+        }
+    }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/StringPresenter.java b/v17/tests/src/android/support/v17/leanback/app/StringPresenter.java
new file mode 100644
index 0000000..e6e0793
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/StringPresenter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.graphics.Color;
+import android.support.v17.leanback.widget.Presenter;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * @hide from javadoc
+ */
+public class StringPresenter extends Presenter {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "StringPresenter";
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent) {
+        if (DEBUG) Log.d(TAG, "onCreateViewHolder");
+        TextView tv = new TextView(parent.getContext());
+        tv.setFocusable(true);
+        tv.setFocusableInTouchMode(true);
+        tv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 200));
+        tv.setBackgroundColor(Color.CYAN);
+        tv.setTextColor(Color.BLACK);
+        return new ViewHolder(tv);
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder viewHolder, Object item) {
+        if (DEBUG) Log.d(TAG, "onBindViewHolder for " + item.toString());
+        ((TextView) viewHolder.view).setText(item.toString());
+    }
+
+    @Override
+    public void onUnbindViewHolder(ViewHolder viewHolder) {
+        if (DEBUG) Log.d(TAG, "onUnbindViewHolder");
+    }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java b/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
index 145ae48..902a665 100644
--- a/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
+++ b/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
@@ -360,7 +360,8 @@
                 holder.mItemAlignment = null;
             }
             if (mChildLayout == -1) {
-                ((TextView) holder.itemView).setText("Item "+mItemLengths[position]);
+                ((TextView) holder.itemView).setText("Item "+mItemLengths[position]
+                        + " type=" + getItemViewType(position));
                 boolean focusable = true;
                 if (mItemFocusables != null) {
                     focusable = mItemFocusables[position];
@@ -370,7 +371,8 @@
                 holder.itemView.setBackgroundColor(Color.LTGRAY);
             } else {
                 if (holder.itemView instanceof TextView) {
-                    ((TextView) holder.itemView).setText("Item "+mItemLengths[position]);
+                    ((TextView) holder.itemView).setText("Item "+mItemLengths[position]
+                            + " type=" + getItemViewType(position));
                 }
             }
             updateSize(holder.itemView, position);
@@ -380,6 +382,7 @@
         public int getItemCount() {
             return mNumItems;
         }
+
     }
 
     void updateSize(View view, int position) {
diff --git a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
index e9e53e4..335f449 100644
--- a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -21,6 +21,7 @@
 import android.text.Spannable;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -105,6 +106,23 @@
         Thread.sleep(500);
     }
 
+    protected void waitForScrollIdleAndItemAnimation(Runnable verify) throws Throwable {
+        waitForScrollIdle();
+        waitForItemAnimation();
+        verify.run();
+    }
+
+    protected void waitForItemAnimation() throws Throwable {
+        Thread.sleep(100);
+        while (mGridView.getItemAnimator() != null && mGridView.getItemAnimator().isRunning()) {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                break;
+            }
+        }
+    }
+
     /**
      * Wait for grid view stop scroll and optionally verify state of grid view.
      */
@@ -1161,12 +1179,12 @@
         initActivity(intent);
 
         mGridView.setSelectedPositionSmooth(0);
-        waitForScrollIdle(mVerifyLayout);
+        waitForScrollIdleAndItemAnimation(mVerifyLayout);
 
         for (int i = 0; i < pressDown; i++) {
             sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
         }
-        waitForScrollIdle(mVerifyLayout);
+        waitForScrollIdleAndItemAnimation(mVerifyLayout);
         assertFalse(mGridView.isFocused());
 
     }
@@ -1570,6 +1588,40 @@
                 ((VerticalGridViewEx) mGridView).mSmoothScrollByCalled < 10);
     }
 
+    public void testSmoothscrollerCancelled() throws Throwable {
+        mInstrumentation = getInstrumentation();
+        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 680;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(0);
+        waitForScrollIdle(mVerifyLayout);
+        assertTrue(mGridView.getChildAt(0).hasFocus());
+
+        int targetPosition = items.length - 1;
+        mGridView.setSelectedPositionSmooth(targetPosition);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.stopScroll();
+            }
+        });
+        Thread.sleep(100);
+        assertEquals(mGridView.getSelectedPosition(), targetPosition);
+        assertSame(mGridView.getLayoutManager().findViewByPosition(targetPosition),
+                mGridView.findFocus());
+    }
+
     public void testSetNumRowsAndAddItem() throws Throwable {
         mInstrumentation = getInstrumentation();
         Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
@@ -1656,7 +1708,7 @@
                 mGridView.setSelectedPositionSmooth(0);
             }
         });
-        waitForScrollIdle(mVerifyLayout);
+        waitForScrollIdleAndItemAnimation(mVerifyLayout);
         verifyMargin();
 
         runTestOnUiThread(new Runnable() {
@@ -1664,7 +1716,7 @@
                 mGridView.setSelectedPositionSmooth(1);
             }
         });
-        waitForScrollIdle(mVerifyLayout);
+        waitForScrollIdleAndItemAnimation(mVerifyLayout);
         verifyMargin();
     }
 
@@ -1735,7 +1787,7 @@
                 mGridView.setSelectedPositionSmooth(1);
             }
         });
-        waitForScrollIdle(mVerifyLayout);
+        waitForScrollIdleAndItemAnimation(mVerifyLayout);
         assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
         assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
         assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
@@ -1753,7 +1805,7 @@
                 mGridView.setSelectedPositionSmooth(0);
             }
         });
-        waitForScrollIdle(mVerifyLayout);
+        waitForScrollIdleAndItemAnimation(mVerifyLayout);
         assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
         assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
         assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
@@ -1835,6 +1887,20 @@
         }
     }
 
+    static class ChangeableViewTypesProvider implements ViewTypeProvider {
+        static SparseIntArray sViewTypes = new SparseIntArray();
+        @Override
+        public int getViewType(int position) {
+            return sViewTypes.get(position);
+        }
+        public static void clear() {
+            sViewTypes.clear();
+        }
+        public static void setViewType(int position, int type) {
+            sViewTypes.put(position, type);
+        }
+    }
+
     static class PositionItemAlignmentFacetProviderForRelativeLayout1
             implements ItemAlignmentFacetProvider {
         ItemAlignmentFacet mMultipleFacet;
@@ -2050,6 +2116,38 @@
         assertEquals(0, mGridView.getSelectedPosition());
     }
 
+    public void testNotifyItemTypeChangedSelectionEvent() throws Throwable {
+        mInstrumentation = getInstrumentation();
+        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                ChangeableViewTypesProvider.class.getName());
+        ChangeableViewTypesProvider.clear();
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final ArrayList<Integer> selectedLog = new ArrayList<Integer>();
+        mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+                selectedLog.add(position);
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                ChangeableViewTypesProvider.setViewType(0, 1);
+                mGridView.getAdapter().notifyItemChanged(0, 1);
+            }
+        });
+        waitForTransientStateGone(null);
+        assertEquals(0, mGridView.getSelectedPosition());
+        assertEquals(selectedLog.size(), 1);
+        assertEquals((int) selectedLog.get(0), 0);
+    }
+
     public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable {
         mInstrumentation = getInstrumentation();
         Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
diff --git a/v17/tests/src/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java b/v17/tests/src/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
new file mode 100644
index 0000000..e7ec4bf
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.test.AndroidTestCase;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+
+public class ShadowOverlayContainerTest extends AndroidTestCase {
+
+    public void testWrapContent() {
+        FrameLayout frameLayout = new FrameLayout(getContext());
+        TextView textView = new TextView(getContext());
+        textView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.WRAP_CONTENT));
+        textView.setText("abc");
+        ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+        container.initialize(true, true, true);
+        container.wrap(textView);
+        frameLayout.addView(container);
+        frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+        frameLayout.layout(0, 0, 500, 500);
+        assertTrue(textView.getWidth() > 0);
+        assertTrue(textView.getWidth() < 500);
+        assertTrue(textView.getHeight() > 0);
+        assertTrue(textView.getHeight() < 500);
+        assertEquals(container.getWidth(), textView.getWidth());
+        assertEquals(container.getHeight(), textView.getHeight());
+
+        // change layout size of textView after wrap()
+        textView.setLayoutParams(new FrameLayout.LayoutParams(123, 123));
+        frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+        frameLayout.layout(0, 0, 500, 500);
+        assertTrue(textView.getWidth() == 123);
+        assertTrue(textView.getHeight() == 123);
+        assertEquals(container.getWidth(), textView.getWidth());
+        assertEquals(container.getHeight(), textView.getHeight());
+    }
+
+    public void testFixedSize() {
+        FrameLayout frameLayout = new FrameLayout(getContext());
+        TextView textView = new TextView(getContext());
+        textView.setLayoutParams(new FrameLayout.LayoutParams(200, LayoutParams.WRAP_CONTENT));
+        textView.setText("abc");
+        ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+        container.initialize(true, true, true);
+        container.wrap(textView);
+        frameLayout.addView(container);
+        frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+        frameLayout.layout(0, 0, 500, 500);
+        assertTrue(textView.getWidth() == 200);
+        assertTrue(textView.getHeight() > 0);
+        assertTrue(textView.getHeight() < 500);
+        assertEquals(container.getWidth(), textView.getWidth());
+        assertEquals(container.getHeight(), textView.getHeight());
+
+        // change layout size of textView after wrap()
+        textView.setLayoutParams(new FrameLayout.LayoutParams(123, 123));
+        frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+        frameLayout.layout(0, 0, 500, 500);
+        assertTrue(textView.getWidth() == 123);
+        assertTrue(textView.getHeight() == 123);
+        assertEquals(container.getWidth(), textView.getWidth());
+        assertEquals(container.getHeight(), textView.getHeight());
+    }
+
+    public void testMatchParent() {
+        FrameLayout frameLayout = new FrameLayout(getContext());
+        TextView textView = new TextView(getContext());
+        textView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.WRAP_CONTENT));
+        textView.setText("abc");
+        ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+        container.initialize(true, true, true);
+        container.wrap(textView);
+        frameLayout.addView(container);
+        frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+        frameLayout.layout(0, 0, 500, 500);
+        assertTrue(textView.getWidth() == 500);
+        assertTrue(textView.getHeight() > 0);
+        assertTrue(textView.getHeight() < 500);
+        assertEquals(container.getWidth(), textView.getWidth());
+        assertEquals(container.getHeight(), textView.getHeight());
+    }
+}
diff --git a/v4/Android.mk b/v4/Android.mk
index 2050725..4336e40 100644
--- a/v4/Android.mk
+++ b/v4/Android.mk
@@ -22,6 +22,9 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-annotations
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files := $(LOCAL_SRC_FILES)
+support_module_java_libraries := android-support-annotations
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Eclair APIs.
@@ -32,6 +35,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-donut
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Eclair MR1 APIs.
@@ -42,6 +47,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-eclair
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Froyo APIs.
@@ -52,6 +59,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-eclair-mr1
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Gingerbread APIs.
@@ -62,6 +71,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-froyo
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Honeycomb APIs.
@@ -72,6 +83,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-gingerbread
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Honeycomb MR1 APIs.
@@ -82,6 +95,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-honeycomb
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Honeycomb MR2 APIs.
@@ -92,6 +107,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-honeycomb-mr1
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Ice Cream Sandwich APIs.
@@ -102,6 +119,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-honeycomb-mr2
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Ice Cream Sandwich MR1 APIs.
@@ -112,6 +131,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-ics
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of JellyBean APIs.
@@ -122,6 +143,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-ics-mr1
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of JellyBean MR1 APIs.
@@ -132,6 +155,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-jellybean
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of JellyBean MR2 APIs.
@@ -142,6 +167,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-jellybean-mr1
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of KitKat APIs.
@@ -152,6 +179,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-jellybean-mr2
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of V20 APIs.
@@ -162,16 +191,33 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-kitkat
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
+# -----------------------------------------------------------------------
+
+# A helper sub-library that allows to use Lollipop internal APIs.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v4-api21-internal
+LOCAL_SDK_VERSION := 21
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, api21/android/content/pm) \
+    $(call all-java-files-under, api21/android/service/media)
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_JAVA_LIBRARY)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of Lollipop APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v4-api21
 LOCAL_SDK_VERSION := 21
-LOCAL_SRC_FILES := $(call all-java-files-under, api21)
+LOCAL_SRC_FILES := $(call all-java-files-under, api21/android/support)
+LOCAL_JAVA_LIBRARIES := android-support-v4-api21-internal
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-api20
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of V22 APIs.
@@ -182,6 +228,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-api21
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # A helper sub-library that makes direct use of V23 APIs.
@@ -189,9 +237,12 @@
 LOCAL_MODULE := android-support-v4-api23
 LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := $(call all-java-files-under, api23)
+LOCAL_JAVA_LIBRARIES := android-support-v4-api21-internal
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-api22
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # -----------------------------------------------------------------------
 
 # Here is the final static library that apps can link against.
@@ -204,11 +255,12 @@
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4-api23
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+support_module_aidl_includes := $(LOCAL_AIDL_INCLUDES)
+
 # API Check
 # ---------------------------------------------
 support_module := $(LOCAL_MODULE)
 support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
-support_module_java_libraries := android-support-v4
 support_module_java_packages := android.support.v4.*
 include $(SUPPORT_API_CHECK)
diff --git a/v4/api/23.txt b/v4/api/23.0.0.txt
similarity index 100%
rename from v4/api/23.txt
rename to v4/api/23.0.0.txt
diff --git a/v4/api/23.1.0.txt b/v4/api/23.1.0.txt
new file mode 100644
index 0000000..ccefe22
--- /dev/null
+++ b/v4/api/23.1.0.txt
@@ -0,0 +1,3520 @@
+package android.support.v4.accessibilityservice {
+
+  public class AccessibilityServiceInfoCompat {
+    method public static java.lang.String capabilityToString(int);
+    method public static java.lang.String feedbackTypeToString(int);
+    method public static java.lang.String flagToString(int);
+    method public static boolean getCanRetrieveWindowContent(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static java.lang.String getDescription(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static java.lang.String getId(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static android.content.pm.ResolveInfo getResolveInfo(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static java.lang.String getSettingsActivityName(android.accessibilityservice.AccessibilityServiceInfo);
+    field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+    field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+    field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+    field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+  }
+
+}
+
+package android.support.v4.animation {
+
+  public abstract class AnimatorCompatHelper {
+    method public static void clearInterpolator(android.view.View);
+    method public static android.support.v4.animation.ValueAnimatorCompat emptyValueAnimator();
+  }
+
+  public abstract interface AnimatorListenerCompat {
+    method public abstract void onAnimationCancel(android.support.v4.animation.ValueAnimatorCompat);
+    method public abstract void onAnimationEnd(android.support.v4.animation.ValueAnimatorCompat);
+    method public abstract void onAnimationRepeat(android.support.v4.animation.ValueAnimatorCompat);
+    method public abstract void onAnimationStart(android.support.v4.animation.ValueAnimatorCompat);
+  }
+
+  public abstract interface AnimatorUpdateListenerCompat {
+    method public abstract void onAnimationUpdate(android.support.v4.animation.ValueAnimatorCompat);
+  }
+
+  public abstract interface ValueAnimatorCompat {
+    method public abstract void addListener(android.support.v4.animation.AnimatorListenerCompat);
+    method public abstract void addUpdateListener(android.support.v4.animation.AnimatorUpdateListenerCompat);
+    method public abstract void cancel();
+    method public abstract float getAnimatedFraction();
+    method public abstract void setDuration(long);
+    method public abstract void setTarget(android.view.View);
+    method public abstract void start();
+  }
+
+}
+
+package android.support.v4.app {
+
+  public deprecated class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int, int);
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, boolean, int, int, int);
+    method public boolean isDrawerIndicatorEnabled();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void setDrawerIndicatorEnabled(boolean);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void syncState();
+  }
+
+  public static abstract interface ActionBarDrawerToggle.Delegate {
+    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+    method public abstract void setActionBarDescription(int);
+    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+  }
+
+  public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+    method public abstract android.support.v4.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+  }
+
+  public class ActivityCompat extends android.support.v4.content.ContextCompat {
+    ctor public ActivityCompat();
+    method public static void finishAffinity(android.app.Activity);
+    method public static void finishAfterTransition(android.app.Activity);
+    method public 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);
+    method public static void setEnterSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+    method public static void setExitSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, java.lang.String);
+    method public static void startActivity(android.app.Activity, android.content.Intent, android.os.Bundle);
+    method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle);
+    method public static void startPostponedEnterTransition(android.app.Activity);
+  }
+
+  public static abstract interface ActivityCompat.OnRequestPermissionsResultCallback {
+    method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+  }
+
+  public final class ActivityManagerCompat {
+    method public static boolean isLowRamDevice(android.app.ActivityManager);
+  }
+
+  public class ActivityOptionsCompat {
+    ctor protected ActivityOptionsCompat();
+    method public static android.support.v4.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
+    method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.support.v4.util.Pair<android.view.View, java.lang.String>...);
+    method public static android.support.v4.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+    method public android.os.Bundle toBundle();
+    method public void update(android.support.v4.app.ActivityOptionsCompat);
+  }
+
+  public class AppOpsManagerCompat {
+    ctor public AppOpsManagerCompat();
+    method public static int noteOp(android.content.Context, java.lang.String, int, java.lang.String);
+    method public static int noteProxyOp(android.content.Context, java.lang.String, java.lang.String);
+    method public static java.lang.String permissionToOp(java.lang.String);
+    field public static final int MODE_ALLOWED = 0; // 0x0
+    field public static final int MODE_DEFAULT = 3; // 0x3
+    field public static final int MODE_IGNORED = 1; // 0x1
+  }
+
+   abstract class BaseFragmentActivityDonut extends android.app.Activity {
+  }
+
+   abstract class BaseFragmentActivityHoneycomb extends android.support.v4.app.BaseFragmentActivityDonut {
+  }
+
+  public class BundleCompat {
+    ctor public BundleCompat();
+    method public static android.os.IBinder getBinder(android.os.Bundle, java.lang.String);
+    method public static void putBinder(android.os.Bundle, java.lang.String, android.os.IBinder);
+  }
+
+  public class DialogFragment extends android.support.v4.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method public android.app.Dialog getDialog();
+    method public boolean getShowsDialog();
+    method public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method public android.app.Dialog onCreateDialog(android.os.Bundle);
+    method public void onDismiss(android.content.DialogInterface);
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, int);
+    method public void show(android.support.v4.app.FragmentManager, java.lang.String);
+    method public int show(android.support.v4.app.FragmentTransaction, java.lang.String);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements android.content.ComponentCallbacks android.view.View.OnCreateContextMenuListener {
+    ctor public Fragment();
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final boolean equals(java.lang.Object);
+    method public final android.support.v4.app.FragmentActivity getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle getArguments();
+    method public final android.support.v4.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context getContext();
+    method public java.lang.Object getEnterTransition();
+    method public java.lang.Object getExitTransition();
+    method public final android.support.v4.app.FragmentManager getFragmentManager();
+    method public final java.lang.Object getHost();
+    method public final int getId();
+    method public android.support.v4.app.LoaderManager getLoaderManager();
+    method public final android.support.v4.app.Fragment getParentFragment();
+    method public java.lang.Object getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method public final boolean getRetainInstance();
+    method public java.lang.Object getReturnTransition();
+    method public java.lang.Object getSharedElementEnterTransition();
+    method public java.lang.Object getSharedElementReturnTransition();
+    method public final java.lang.String getString(int);
+    method public final java.lang.String getString(int, java.lang.Object...);
+    method public final java.lang.String getTag();
+    method public final android.support.v4.app.Fragment getTargetFragment();
+    method public final int getTargetRequestCode();
+    method public final java.lang.CharSequence getText(int);
+    method public boolean getUserVisibleHint();
+    method public android.view.View getView();
+    method public final int hashCode();
+    method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String);
+    method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isVisible();
+    method public void onActivityCreated(android.os.Bundle);
+    method public void onActivityResult(int, int, android.content.Intent);
+    method public void onAttach(android.content.Context);
+    method public deprecated void onAttach(android.app.Activity);
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public boolean onContextItemSelected(android.view.MenuItem);
+    method public void onCreate(android.os.Bundle);
+    method public android.view.animation.Animation onCreateAnimation(int, boolean, int);
+    method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
+    method public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDestroy();
+    method public void onDestroyOptionsMenu();
+    method public void onDestroyView();
+    method public void onDetach();
+    method public void onHiddenChanged(boolean);
+    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+    method public void onLowMemory();
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void onOptionsMenuClosed(android.view.Menu);
+    method public void onPause();
+    method public void onPrepareOptionsMenu(android.view.Menu);
+    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
+    method public void onResume();
+    method public void onSaveInstanceState(android.os.Bundle);
+    method public void onStart();
+    method public void onStop();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
+    method public void onViewStateRestored(android.os.Bundle);
+    method public void registerForContextMenu(android.view.View);
+    method public final void requestPermissions(java.lang.String[], int);
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle);
+    method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setEnterTransition(java.lang.Object);
+    method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setExitTransition(java.lang.Object);
+    method public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(android.support.v4.app.Fragment.SavedState);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(java.lang.Object);
+    method public void setRetainInstance(boolean);
+    method public void setReturnTransition(java.lang.Object);
+    method public void setSharedElementEnterTransition(java.lang.Object);
+    method public void setSharedElementReturnTransition(java.lang.Object);
+    method public void setTargetFragment(android.support.v4.app.Fragment, int);
+    method public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(java.lang.String);
+    method public void startActivity(android.content.Intent);
+    method public void startActivityForResult(android.content.Intent, int);
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.app.Fragment.SavedState> CREATOR;
+  }
+
+  public class FragmentActivity extends android.support.v4.app.BaseFragmentActivityHoneycomb implements android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback {
+    ctor public FragmentActivity();
+    method public java.lang.Object getLastCustomNonConfigurationInstance();
+    method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+    method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+    method public final android.support.v4.media.session.MediaControllerCompat getSupportMediaController();
+    method public void onAttachFragment(android.support.v4.app.Fragment);
+    method protected void onResumeFragments();
+    method public java.lang.Object onRetainCustomNonConfigurationInstance();
+    method public final java.lang.Object onRetainNonConfigurationInstance();
+    method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public final void setSupportMediaController(android.support.v4.media.session.MediaControllerCompat);
+    method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+    method public void supportFinishAfterTransition();
+    method public void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method public abstract android.view.View onFindViewById(int);
+    method public abstract boolean onHasView();
+  }
+
+  public class FragmentController {
+    method public void attachHost(android.support.v4.app.Fragment);
+    method public static final android.support.v4.app.FragmentController createController(android.support.v4.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method public void doLoaderDestroy();
+    method public void doLoaderRetain();
+    method public void doLoaderStart();
+    method public void doLoaderStop(boolean);
+    method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public boolean execPendingActions();
+    method public java.util.List<android.support.v4.app.Fragment> getActiveFragments(java.util.List<android.support.v4.app.Fragment>);
+    method public int getActiveFragmentsCount();
+    method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+    method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public void reportLoaderStart();
+    method public void restoreAllState(android.os.Parcelable, java.util.List<android.support.v4.app.Fragment>);
+    method public void restoreLoaderNonConfig(android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager>);
+    method public android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager> retainLoaderNonConfig();
+    method public java.util.List<android.support.v4.app.Fragment> retainNonConfig();
+    method public android.os.Parcelable saveAllState();
+  }
+
+  public abstract class FragmentHostCallback extends android.support.v4.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public android.view.View onFindViewById(int);
+    method public abstract E onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method public void onRequestPermissionsFromFragment(android.support.v4.app.Fragment, java.lang.String[], int);
+    method public boolean onShouldSaveFragmentState(android.support.v4.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(java.lang.String);
+    method public void onStartActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager {
+    ctor public FragmentManager();
+    method public abstract void addOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+    method public abstract android.support.v4.app.FragmentTransaction beginTransaction();
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public abstract boolean executePendingTransactions();
+    method public abstract android.support.v4.app.Fragment findFragmentById(int);
+    method public abstract android.support.v4.app.Fragment findFragmentByTag(java.lang.String);
+    method public abstract android.support.v4.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public abstract int getBackStackEntryCount();
+    method public abstract android.support.v4.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+    method public abstract boolean isDestroyed();
+    method public abstract void popBackStack();
+    method public abstract void popBackStack(java.lang.String, int);
+    method public abstract void popBackStack(int, int);
+    method public abstract boolean popBackStackImmediate();
+    method public abstract boolean popBackStackImmediate(java.lang.String, int);
+    method public abstract boolean popBackStackImmediate(int, int);
+    method public abstract void putFragment(android.os.Bundle, java.lang.String, android.support.v4.app.Fragment);
+    method public abstract void removeOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+    method public abstract android.support.v4.app.Fragment.SavedState saveFragmentInstanceState(android.support.v4.app.Fragment);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static abstract interface FragmentManager.BackStackEntry {
+    method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
+    method public abstract int getBreadCrumbShortTitleRes();
+    method public abstract java.lang.CharSequence getBreadCrumbTitle();
+    method public abstract int getBreadCrumbTitleRes();
+    method public abstract int getId();
+    method public abstract java.lang.String getName();
+  }
+
+  public static abstract interface FragmentManager.OnBackStackChangedListener {
+    method public abstract void onBackStackChanged();
+  }
+
+  public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentPagerAdapter(android.support.v4.app.FragmentManager);
+    method public abstract android.support.v4.app.Fragment getItem(int);
+    method public long getItemId(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public abstract class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
+    ctor public FragmentStatePagerAdapter(android.support.v4.app.FragmentManager);
+    method public abstract android.support.v4.app.Fragment getItem(int);
+    method public boolean isViewFromObject(android.view.View, java.lang.Object);
+  }
+
+  public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor public FragmentTabHost(android.content.Context);
+    ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
+    method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
+    method public void onTabChanged(java.lang.String);
+    method public void setup(android.content.Context, android.support.v4.app.FragmentManager);
+    method public void setup(android.content.Context, android.support.v4.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor public FragmentTransaction();
+    method public abstract android.support.v4.app.FragmentTransaction add(android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction addSharedElement(android.view.View, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction addToBackStack(java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction attach(android.support.v4.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method public abstract android.support.v4.app.FragmentTransaction detach(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction disallowAddToBackStack();
+    method public abstract android.support.v4.app.FragmentTransaction hide(android.support.v4.app.Fragment);
+    method public abstract boolean isAddToBackStackAllowed();
+    method public abstract boolean isEmpty();
+    method public abstract android.support.v4.app.FragmentTransaction remove(android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment);
+    method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment, java.lang.String);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(int);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(int);
+    method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
+    method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int);
+    method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+    method public abstract android.support.v4.app.FragmentTransaction setTransition(int);
+    method public abstract android.support.v4.app.FragmentTransaction setTransitionStyle(int);
+    method public abstract android.support.v4.app.FragmentTransaction show(android.support.v4.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  public class ListFragment extends android.support.v4.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public void setEmptyText(java.lang.CharSequence);
+    method public void setListAdapter(android.widget.ListAdapter);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+  public abstract class LoaderManager {
+    ctor public LoaderManager();
+    method public abstract void destroyLoader(int);
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public abstract android.support.v4.content.Loader<D> getLoader(int);
+    method public boolean hasRunningLoaders();
+    method public abstract android.support.v4.content.Loader<D> initLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract android.support.v4.content.Loader<D> restartLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+  }
+
+  public static abstract interface LoaderManager.LoaderCallbacks {
+    method public abstract android.support.v4.content.Loader<D> onCreateLoader(int, android.os.Bundle);
+    method public abstract void onLoadFinished(android.support.v4.content.Loader<D>, D);
+    method public abstract void onLoaderReset(android.support.v4.content.Loader<D>);
+  }
+
+  public class NavUtils {
+    method public static android.content.Intent getParentActivityIntent(android.app.Activity);
+    method public static android.content.Intent getParentActivityIntent(android.content.Context, java.lang.Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static android.content.Intent getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static java.lang.String getParentActivityName(android.app.Activity);
+    method public static java.lang.String getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void navigateUpFromSameTask(android.app.Activity);
+    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    field public static final java.lang.String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+  }
+
+  public class NotificationCompat {
+    ctor public NotificationCompat();
+    method public static android.support.v4.app.NotificationCompat.Action getAction(android.app.Notification, int);
+    method public static int getActionCount(android.app.Notification);
+    method public static java.lang.String getCategory(android.app.Notification);
+    method public static android.os.Bundle getExtras(android.app.Notification);
+    method public static java.lang.String getGroup(android.app.Notification);
+    method public static boolean getLocalOnly(android.app.Notification);
+    method public static java.lang.String getSortKey(android.app.Notification);
+    method public static boolean isGroupSummary(android.app.Notification);
+    field public static final java.lang.String CATEGORY_ALARM = "alarm";
+    field public static final java.lang.String CATEGORY_CALL = "call";
+    field public static final java.lang.String CATEGORY_EMAIL = "email";
+    field public static final java.lang.String CATEGORY_ERROR = "err";
+    field public static final java.lang.String CATEGORY_EVENT = "event";
+    field public static final java.lang.String CATEGORY_MESSAGE = "msg";
+    field public static final java.lang.String CATEGORY_PROGRESS = "progress";
+    field public static final java.lang.String CATEGORY_PROMO = "promo";
+    field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final java.lang.String CATEGORY_SERVICE = "service";
+    field public static final java.lang.String CATEGORY_SOCIAL = "social";
+    field public static final java.lang.String CATEGORY_STATUS = "status";
+    field public static final java.lang.String CATEGORY_SYSTEM = "sys";
+    field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+    field public static final int COLOR_DEFAULT = 0; // 0x0
+    field public static final int DEFAULT_ALL = -1; // 0xffffffff
+    field public static final int DEFAULT_LIGHTS = 4; // 0x4
+    field public static final int DEFAULT_SOUND = 1; // 0x1
+    field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+    field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession";
+    field public static final java.lang.String EXTRA_PEOPLE = "android.people";
+    field public static final java.lang.String EXTRA_PICTURE = "android.picture";
+    field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
+    field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
+    field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
+    field public static final java.lang.String EXTRA_SUB_TEXT = "android.subText";
+    field public static final java.lang.String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
+    field public static final java.lang.String EXTRA_TEXT = "android.text";
+    field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final java.lang.String EXTRA_TITLE = "android.title";
+    field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
+    field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+    field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+    field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
+    field public static final int FLAG_INSISTENT = 4; // 0x4
+    field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+    field public static final int FLAG_NO_CLEAR = 32; // 0x20
+    field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+    field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+    field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+    field public static final int PRIORITY_DEFAULT = 0; // 0x0
+    field public static final int PRIORITY_HIGH = 1; // 0x1
+    field public static final int PRIORITY_LOW = -1; // 0xffffffff
+    field public static final int PRIORITY_MAX = 2; // 0x2
+    field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+    field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+    field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+    field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+    field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+  }
+
+  public static class NotificationCompat.Action extends android.support.v4.app.NotificationCompatBase.Action {
+    ctor public NotificationCompat.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.PendingIntent getActionIntent();
+    method public android.os.Bundle getExtras();
+    method public int getIcon();
+    method public android.support.v4.app.RemoteInput[] getRemoteInputs();
+    method public java.lang.CharSequence getTitle();
+    field public android.app.PendingIntent actionIntent;
+    field public int icon;
+    field public java.lang.CharSequence title;
+  }
+
+  public static final class NotificationCompat.Action.Builder {
+    ctor public NotificationCompat.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+    ctor public NotificationCompat.Action.Builder(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Action.Builder addRemoteInput(android.support.v4.app.RemoteInput);
+    method public android.support.v4.app.NotificationCompat.Action build();
+    method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Extender);
+    method public android.os.Bundle getExtras();
+  }
+
+  public static abstract interface NotificationCompat.Action.Extender {
+    method public abstract android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+  }
+
+  public static final class NotificationCompat.Action.WearableExtender implements android.support.v4.app.NotificationCompat.Action.Extender {
+    ctor public NotificationCompat.Action.WearableExtender();
+    ctor public NotificationCompat.Action.WearableExtender(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender clone();
+    method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+    method public java.lang.CharSequence getCancelLabel();
+    method public java.lang.CharSequence getConfirmLabel();
+    method public java.lang.CharSequence getInProgressLabel();
+    method public boolean isAvailableOffline();
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.BigPictureStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigPictureStyle();
+    ctor public NotificationCompat.BigPictureStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigPictureStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.BigTextStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigTextStyle();
+    ctor public NotificationCompat.BigTextStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle bigText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.BigTextStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static class NotificationCompat.Builder {
+    ctor public NotificationCompat.Builder(android.content.Context);
+    method public android.support.v4.app.NotificationCompat.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder addAction(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Builder addPerson(java.lang.String);
+    method public android.app.Notification build();
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Extender);
+    method public android.os.Bundle getExtras();
+    method public deprecated android.app.Notification getNotification();
+    method protected static java.lang.CharSequence limitCharSequenceLength(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setAutoCancel(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setCategory(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setColor(int);
+    method public android.support.v4.app.NotificationCompat.Builder setContent(android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setContentInfo(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder setContentText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setDefaults(int);
+    method public android.support.v4.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setGroup(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setGroupSummary(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.Builder setLights(int, int, int);
+    method public android.support.v4.app.NotificationCompat.Builder setLocalOnly(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setNumber(int);
+    method public android.support.v4.app.NotificationCompat.Builder setOngoing(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setPriority(int);
+    method public android.support.v4.app.NotificationCompat.Builder setProgress(int, int, boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setPublicVersion(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.Builder setShowWhen(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int);
+    method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int, int);
+    method public android.support.v4.app.NotificationCompat.Builder setSortKey(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri);
+    method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri, int);
+    method public android.support.v4.app.NotificationCompat.Builder setStyle(android.support.v4.app.NotificationCompat.Style);
+    method public android.support.v4.app.NotificationCompat.Builder setSubText(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+    method public android.support.v4.app.NotificationCompat.Builder setUsesChronometer(boolean);
+    method public android.support.v4.app.NotificationCompat.Builder setVibrate(long[]);
+    method public android.support.v4.app.NotificationCompat.Builder setVisibility(int);
+    method public android.support.v4.app.NotificationCompat.Builder setWhen(long);
+    field public java.util.ArrayList<java.lang.String> mPeople;
+  }
+
+  public static final class NotificationCompat.CarExtender implements android.support.v4.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.CarExtender();
+    ctor public NotificationCompat.CarExtender(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+    method public int getColor();
+    method public android.graphics.Bitmap getLargeIcon();
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation getUnreadConversation();
+    method public android.support.v4.app.NotificationCompat.CarExtender setColor(int);
+    method public android.support.v4.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.CarExtender setUnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation);
+  }
+
+  public static class NotificationCompat.CarExtender.UnreadConversation extends android.support.v4.app.NotificationCompatBase.UnreadConversation {
+    method public long getLatestTimestamp();
+    method public java.lang.String[] getMessages();
+    method public java.lang.String getParticipant();
+    method public java.lang.String[] getParticipants();
+    method public android.app.PendingIntent getReadPendingIntent();
+    method public android.support.v4.app.RemoteInput getRemoteInput();
+    method public android.app.PendingIntent getReplyPendingIntent();
+  }
+
+  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation build();
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent, android.support.v4.app.RemoteInput);
+  }
+
+  public static abstract interface NotificationCompat.Extender {
+    method public abstract android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+  }
+
+  public static class NotificationCompat.InboxStyle extends android.support.v4.app.NotificationCompat.Style {
+    ctor public NotificationCompat.InboxStyle();
+    ctor public NotificationCompat.InboxStyle(android.support.v4.app.NotificationCompat.Builder);
+    method public android.support.v4.app.NotificationCompat.InboxStyle addLine(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.InboxStyle setBigContentTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.InboxStyle setSummaryText(java.lang.CharSequence);
+  }
+
+  public static abstract class NotificationCompat.Style {
+    ctor public NotificationCompat.Style();
+    method public android.app.Notification build();
+    method public void setBuilder(android.support.v4.app.NotificationCompat.Builder);
+  }
+
+  public static final class NotificationCompat.WearableExtender implements android.support.v4.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.WearableExtender();
+    ctor public NotificationCompat.WearableExtender(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addAction(android.support.v4.app.NotificationCompat.Action);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addActions(java.util.List<android.support.v4.app.NotificationCompat.Action>);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+    method public android.support.v4.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification>);
+    method public android.support.v4.app.NotificationCompat.WearableExtender clearActions();
+    method public android.support.v4.app.NotificationCompat.WearableExtender clearPages();
+    method public android.support.v4.app.NotificationCompat.WearableExtender clone();
+    method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+    method public java.util.List<android.support.v4.app.NotificationCompat.Action> getActions();
+    method public android.graphics.Bitmap getBackground();
+    method public int getContentAction();
+    method public int getContentIcon();
+    method public int getContentIconGravity();
+    method public boolean getContentIntentAvailableOffline();
+    method public int getCustomContentHeight();
+    method public int getCustomSizePreset();
+    method public android.app.PendingIntent getDisplayIntent();
+    method public int getGravity();
+    method public boolean getHintAvoidBackgroundClipping();
+    method public boolean getHintHideIcon();
+    method public int getHintScreenTimeout();
+    method public boolean getHintShowBackgroundOnly();
+    method public java.util.List<android.app.Notification> getPages();
+    method public boolean getStartScrollBottom();
+    method public android.support.v4.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentAction(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIcon(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setGravity(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+    method public android.support.v4.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+    field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field public static final int SIZE_DEFAULT = 0; // 0x0
+    field public static final int SIZE_FULL_SCREEN = 5; // 0x5
+    field public static final int SIZE_LARGE = 4; // 0x4
+    field public static final int SIZE_MEDIUM = 3; // 0x3
+    field public static final int SIZE_SMALL = 2; // 0x2
+    field public static final int SIZE_XSMALL = 1; // 0x1
+    field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+  }
+
+  public class NotificationCompatBase {
+    ctor public NotificationCompatBase();
+  }
+
+  public static abstract class NotificationCompatBase.Action {
+    ctor public NotificationCompatBase.Action();
+    method public abstract android.app.PendingIntent getActionIntent();
+    method public abstract android.os.Bundle getExtras();
+    method public abstract int getIcon();
+    method public abstract android.support.v4.app.RemoteInputCompatBase.RemoteInput[] getRemoteInputs();
+    method public abstract java.lang.CharSequence getTitle();
+  }
+
+  public static abstract class NotificationCompatBase.UnreadConversation {
+    ctor public NotificationCompatBase.UnreadConversation();
+  }
+
+  public final class NotificationCompatExtras {
+    field public static final java.lang.String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+    field public static final java.lang.String EXTRA_GROUP_KEY = "android.support.groupKey";
+    field public static final java.lang.String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+    field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+    field public static final java.lang.String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+    field public static final java.lang.String EXTRA_SORT_KEY = "android.support.sortKey";
+  }
+
+  public abstract class NotificationCompatSideChannelService extends android.app.Service {
+    ctor public NotificationCompatSideChannelService();
+    method public abstract void cancel(java.lang.String, int, java.lang.String);
+    method public abstract void cancelAll(java.lang.String);
+    method public abstract void notify(java.lang.String, int, java.lang.String, android.app.Notification);
+    method public android.os.IBinder onBind(android.content.Intent);
+  }
+
+  public class NotificationManagerCompat {
+    method public void cancel(int);
+    method public void cancel(java.lang.String, int);
+    method public void cancelAll();
+    method public static android.support.v4.app.NotificationManagerCompat from(android.content.Context);
+    method public static java.util.Set<java.lang.String> getEnabledListenerPackages(android.content.Context);
+    method public void notify(int, android.app.Notification);
+    method public void notify(java.lang.String, int, android.app.Notification);
+    field public static final java.lang.String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+    field public static final java.lang.String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+  }
+
+  public class RemoteInput extends android.support.v4.app.RemoteInputCompatBase.RemoteInput {
+    method public static void addResultsToIntent(android.support.v4.app.RemoteInput[], android.content.Intent, android.os.Bundle);
+    method public boolean getAllowFreeFormInput();
+    method public java.lang.CharSequence[] getChoices();
+    method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.String getResultKey();
+    method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+  }
+
+  public static final class RemoteInput.Builder {
+    ctor public RemoteInput.Builder(java.lang.String);
+    method public android.support.v4.app.RemoteInput.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.RemoteInput build();
+    method public android.os.Bundle getExtras();
+    method public android.support.v4.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method public android.support.v4.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
+    method public android.support.v4.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
+  }
+
+   class RemoteInputCompatBase {
+  }
+
+  public static abstract class RemoteInputCompatBase.RemoteInput {
+    ctor public RemoteInputCompatBase.RemoteInput();
+    method protected abstract boolean getAllowFreeFormInput();
+    method protected abstract java.lang.CharSequence[] getChoices();
+    method protected abstract android.os.Bundle getExtras();
+    method protected abstract java.lang.CharSequence getLabel();
+    method protected abstract java.lang.String getResultKey();
+  }
+
+  public class ServiceCompat {
+    field public static final int START_STICKY = 1; // 0x1
+  }
+
+  public class ShareCompat {
+    ctor public ShareCompat();
+    method public static void configureMenuItem(android.view.MenuItem, android.support.v4.app.ShareCompat.IntentBuilder);
+    method public static void configureMenuItem(android.view.Menu, int, android.support.v4.app.ShareCompat.IntentBuilder);
+    method public static android.content.ComponentName getCallingActivity(android.app.Activity);
+    method public static java.lang.String getCallingPackage(android.app.Activity);
+    field public static final java.lang.String EXTRA_CALLING_ACTIVITY = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+    field public static final java.lang.String EXTRA_CALLING_PACKAGE = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+  }
+
+  public static class ShareCompat.IntentBuilder {
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+    method public android.content.Intent createChooserIntent();
+    method public static android.support.v4.app.ShareCompat.IntentBuilder from(android.app.Activity);
+    method public android.content.Intent getIntent();
+    method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(java.lang.CharSequence);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(int);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailBcc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailCc(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setEmailTo(java.lang.String[]);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setHtmlText(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setStream(android.net.Uri);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setSubject(java.lang.String);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setText(java.lang.CharSequence);
+    method public android.support.v4.app.ShareCompat.IntentBuilder setType(java.lang.String);
+    method public void startChooser();
+  }
+
+  public static class ShareCompat.IntentReader {
+    method public static android.support.v4.app.ShareCompat.IntentReader from(android.app.Activity);
+    method public android.content.ComponentName getCallingActivity();
+    method public android.graphics.drawable.Drawable getCallingActivityIcon();
+    method public android.graphics.drawable.Drawable getCallingApplicationIcon();
+    method public java.lang.CharSequence getCallingApplicationLabel();
+    method public java.lang.String getCallingPackage();
+    method public java.lang.String[] getEmailBcc();
+    method public java.lang.String[] getEmailCc();
+    method public java.lang.String[] getEmailTo();
+    method public java.lang.String getHtmlText();
+    method public android.net.Uri getStream();
+    method public android.net.Uri getStream(int);
+    method public int getStreamCount();
+    method public java.lang.String getSubject();
+    method public java.lang.CharSequence getText();
+    method public java.lang.String getType();
+    method public boolean isMultipleShare();
+    method public boolean isShareIntent();
+    method public boolean isSingleShare();
+  }
+
+  public abstract class SharedElementCallback {
+    ctor public SharedElementCallback();
+    method public android.os.Parcelable onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF);
+    method public android.view.View onCreateSnapshotView(android.content.Context, android.os.Parcelable);
+    method public void onMapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
+    method public void onRejectSharedElements(java.util.List<android.view.View>);
+    method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+    method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+  }
+
+  public class TaskStackBuilder implements java.lang.Iterable {
+    method public android.support.v4.app.TaskStackBuilder addNextIntent(android.content.Intent);
+    method public android.support.v4.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(android.app.Activity);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(java.lang.Class<?>);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+    method public static android.support.v4.app.TaskStackBuilder create(android.content.Context);
+    method public android.content.Intent editIntentAt(int);
+    method public static deprecated android.support.v4.app.TaskStackBuilder from(android.content.Context);
+    method public deprecated android.content.Intent getIntent(int);
+    method public int getIntentCount();
+    method public android.content.Intent[] getIntents();
+    method public android.app.PendingIntent getPendingIntent(int, int);
+    method public android.app.PendingIntent getPendingIntent(int, int, android.os.Bundle);
+    method public deprecated java.util.Iterator<android.content.Intent> iterator();
+    method public void startActivities();
+    method public void startActivities(android.os.Bundle);
+  }
+
+  public static abstract interface TaskStackBuilder.SupportParentable {
+    method public abstract android.content.Intent getSupportParentActivityIntent();
+  }
+
+}
+
+package android.support.v4.content {
+
+  public abstract class AsyncTaskLoader extends android.support.v4.content.Loader {
+    ctor public AsyncTaskLoader(android.content.Context);
+    method public void cancelLoadInBackground();
+    method public boolean isLoadInBackgroundCanceled();
+    method public abstract D loadInBackground();
+    method public void onCanceled(D);
+    method protected D onLoadInBackground();
+    method public void setUpdateThrottle(long);
+  }
+
+  public class ContentResolverCompat {
+    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.support.v4.os.CancellationSignal);
+  }
+
+  public class ContextCompat {
+    ctor public ContextCompat();
+    method public static int checkSelfPermission(android.content.Context, java.lang.String);
+    method public final java.io.File getCodeCacheDir(android.content.Context);
+    method public static final int getColor(android.content.Context, int);
+    method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
+    method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
+    method public static java.io.File[] getExternalCacheDirs(android.content.Context);
+    method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
+    method public final java.io.File getNoBackupFilesDir(android.content.Context);
+    method public static java.io.File[] getObbDirs(android.content.Context);
+    method public static boolean startActivities(android.content.Context, android.content.Intent[]);
+    method public static boolean startActivities(android.content.Context, android.content.Intent[], android.os.Bundle);
+  }
+
+  public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
+    ctor public CursorLoader(android.content.Context);
+    ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public void deliverResult(android.database.Cursor);
+    method public java.lang.String[] getProjection();
+    method public java.lang.String getSelection();
+    method public java.lang.String[] getSelectionArgs();
+    method public java.lang.String getSortOrder();
+    method public android.net.Uri getUri();
+    method public android.database.Cursor loadInBackground();
+    method public void onCanceled(android.database.Cursor);
+    method public void setProjection(java.lang.String[]);
+    method public void setSelection(java.lang.String);
+    method public void setSelectionArgs(java.lang.String[]);
+    method public void setSortOrder(java.lang.String);
+    method public void setUri(android.net.Uri);
+  }
+
+  public class FileProvider extends android.content.ContentProvider {
+    ctor public FileProvider();
+    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public java.lang.String getType(android.net.Uri);
+    method public static android.net.Uri getUriForFile(android.content.Context, java.lang.String, java.io.File);
+    method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public boolean onCreate();
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+  }
+
+  public class IntentCompat {
+    method public static android.content.Intent makeMainActivity(android.content.ComponentName);
+    method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
+    method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
+    field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
+    field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+    field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
+    field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
+    field public static final int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
+  }
+
+  public class Loader {
+    ctor public Loader(android.content.Context);
+    method public void abandon();
+    method public boolean cancelLoad();
+    method public void commitContentChanged();
+    method public java.lang.String dataToString(D);
+    method public void deliverCancellation();
+    method public void deliverResult(D);
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void forceLoad();
+    method public android.content.Context getContext();
+    method public int getId();
+    method public boolean isAbandoned();
+    method public boolean isReset();
+    method public boolean isStarted();
+    method protected void onAbandon();
+    method protected boolean onCancelLoad();
+    method public void onContentChanged();
+    method protected void onForceLoad();
+    method protected void onReset();
+    method protected void onStartLoading();
+    method protected void onStopLoading();
+    method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+    method public void reset();
+    method public void rollbackContentChanged();
+    method public final void startLoading();
+    method public void stopLoading();
+    method public boolean takeContentChanged();
+    method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+  }
+
+  public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+    ctor public Loader.ForceLoadContentObserver();
+  }
+
+  public static abstract interface Loader.OnLoadCanceledListener {
+    method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
+  }
+
+  public static abstract interface Loader.OnLoadCompleteListener {
+    method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
+  }
+
+  public class LocalBroadcastManager {
+    method public static android.support.v4.content.LocalBroadcastManager getInstance(android.content.Context);
+    method public void registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
+    method public boolean sendBroadcast(android.content.Intent);
+    method public void sendBroadcastSync(android.content.Intent);
+    method public void unregisterReceiver(android.content.BroadcastReceiver);
+  }
+
+  public class ParallelExecutorCompat {
+    ctor public ParallelExecutorCompat();
+    method public static java.util.concurrent.Executor getParallelExecutor();
+  }
+
+  public final class PermissionChecker {
+    method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
+    method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
+    method public static int checkPermission(android.content.Context, java.lang.String, int, int, java.lang.String);
+    method public static int checkSelfPermission(android.content.Context, java.lang.String);
+    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+    field public static final int PERMISSION_GRANTED = 0; // 0x0
+  }
+
+  public static abstract class PermissionChecker.PermissionResult implements java.lang.annotation.Annotation {
+  }
+
+  public class SharedPreferencesCompat {
+    ctor public SharedPreferencesCompat();
+  }
+
+  public static class SharedPreferencesCompat.EditorCompat {
+    method public void apply(android.content.SharedPreferences.Editor);
+    method public static android.support.v4.content.SharedPreferencesCompat.EditorCompat getInstance();
+  }
+
+  public abstract class WakefulBroadcastReceiver extends android.content.BroadcastReceiver {
+    ctor public WakefulBroadcastReceiver();
+    method public static boolean completeWakefulIntent(android.content.Intent);
+    method public static android.content.ComponentName startWakefulService(android.content.Context, android.content.Intent);
+  }
+
+}
+
+package android.support.v4.content.pm {
+
+  public class ActivityInfoCompat {
+    field public static final int CONFIG_UI_MODE = 512; // 0x200
+  }
+
+}
+
+package android.support.v4.content.res {
+
+  public class ResourcesCompat {
+    ctor public ResourcesCompat();
+    method public int getColor(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public android.content.res.ColorStateList getColorStateList(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable getDrawable(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable getDrawableForDensity(android.content.res.Resources, int, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+  }
+
+}
+
+package android.support.v4.database {
+
+  public class DatabaseUtilsCompat {
+    method public static java.lang.String[] appendSelectionArgs(java.lang.String[], java.lang.String[]);
+    method public static java.lang.String concatenateWhere(java.lang.String, java.lang.String);
+  }
+
+}
+
+package android.support.v4.graphics {
+
+  public class BitmapCompat {
+    ctor public BitmapCompat();
+    method public static int getAllocationByteCount(android.graphics.Bitmap);
+    method public static boolean hasMipMap(android.graphics.Bitmap);
+    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+  }
+
+  public class ColorUtils {
+    method public static int HSLToColor(float[]);
+    method public static void RGBToHSL(int, int, int, float[]);
+    method public static double calculateContrast(int, int);
+    method public static double calculateLuminance(int);
+    method public static int calculateMinimumAlpha(int, int, float);
+    method public static void colorToHSL(int, float[]);
+    method public static int compositeColors(int, int);
+    method public static int setAlphaComponent(int, int);
+  }
+
+}
+
+package android.support.v4.graphics.drawable {
+
+  public class DrawableCompat {
+    ctor public DrawableCompat();
+    method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+    method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+    method public static void setLayoutDirection(android.graphics.drawable.Drawable, int);
+    method public static void setTint(android.graphics.drawable.Drawable, int);
+    method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static T unwrap(android.graphics.drawable.Drawable);
+    method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+  }
+
+  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+    method public void draw(android.graphics.Canvas);
+    method public final android.graphics.Bitmap getBitmap();
+    method public float getCornerRadius();
+    method public int getGravity();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public boolean hasAntiAlias();
+    method public boolean hasMipMap();
+    method public boolean isCircular();
+    method public void setAlpha(int);
+    method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setCornerRadius(float);
+    method public void setGravity(int);
+    method public void setMipMap(boolean);
+    method public void setTargetDensity(android.graphics.Canvas);
+    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(int);
+  }
+
+  public class RoundedBitmapDrawableFactory {
+    ctor public RoundedBitmapDrawableFactory();
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap);
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.lang.String);
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+  }
+
+}
+
+package android.support.v4.hardware.display {
+
+  public abstract class DisplayManagerCompat {
+    method public abstract android.view.Display getDisplay(int);
+    method public abstract android.view.Display[] getDisplays();
+    method public abstract android.view.Display[] getDisplays(java.lang.String);
+    method public static android.support.v4.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+    field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+  }
+
+}
+
+package android.support.v4.hardware.fingerprint {
+
+  public class FingerprintManagerCompat {
+    method public void authenticate(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject, int, android.support.v4.os.CancellationSignal, android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler);
+    method public static android.support.v4.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+    method public boolean hasEnrolledFingerprints();
+    method public boolean isHardwareDetected();
+  }
+
+  public static abstract class FingerprintManagerCompat.AuthenticationCallback {
+    ctor public FingerprintManagerCompat.AuthenticationCallback();
+    method public void onAuthenticationError(int, java.lang.CharSequence);
+    method public void onAuthenticationFailed();
+    method public void onAuthenticationHelp(int, java.lang.CharSequence);
+    method public void onAuthenticationSucceeded(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult);
+  }
+
+  public static final class FingerprintManagerCompat.AuthenticationResult {
+    ctor public FingerprintManagerCompat.AuthenticationResult(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject);
+    method public android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject getCryptoObject();
+  }
+
+  public static class FingerprintManagerCompat.CryptoObject {
+    ctor public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+    ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+    ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+    method public javax.crypto.Cipher getCipher();
+    method public javax.crypto.Mac getMac();
+    method public java.security.Signature getSignature();
+  }
+
+}
+
+package android.support.v4.media {
+
+  public final class MediaDescriptionCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.MediaDescriptionCompat fromMediaDescription(java.lang.Object);
+    method public java.lang.CharSequence getDescription();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.Bitmap getIconBitmap();
+    method public android.net.Uri getIconUri();
+    method public java.lang.Object getMediaDescription();
+    method public java.lang.String getMediaId();
+    method public android.net.Uri getMediaUri();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat> CREATOR;
+  }
+
+  public static final class MediaDescriptionCompat.Builder {
+    ctor public MediaDescriptionCompat.Builder();
+    method public android.support.v4.media.MediaDescriptionCompat build();
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setDescription(java.lang.CharSequence);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconBitmap(android.graphics.Bitmap);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconUri(android.net.Uri);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaId(java.lang.String);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaUri(android.net.Uri);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setSubtitle(java.lang.CharSequence);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder setTitle(java.lang.CharSequence);
+  }
+
+  public final class MediaMetadataCompat implements android.os.Parcelable {
+    method public boolean containsKey(java.lang.String);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaMetadataCompat fromMediaMetadata(java.lang.Object);
+    method public android.graphics.Bitmap getBitmap(java.lang.String);
+    method public android.os.Bundle getBundle();
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public long getLong(java.lang.String);
+    method public java.lang.Object getMediaMetadata();
+    method public android.support.v4.media.RatingCompat getRating(java.lang.String);
+    method public java.lang.String getString(java.lang.String);
+    method public java.lang.CharSequence getText(java.lang.String);
+    method public java.util.Set<java.lang.String> keySet();
+    method public int size();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat> CREATOR;
+    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public static final class MediaMetadataCompat.Builder {
+    ctor public MediaMetadataCompat.Builder();
+    ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat);
+    method public android.support.v4.media.MediaMetadataCompat build();
+    method public android.support.v4.media.MediaMetadataCompat.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putLong(java.lang.String, long);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putRating(java.lang.String, android.support.v4.media.RatingCompat);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putString(java.lang.String, java.lang.String);
+    method public android.support.v4.media.MediaMetadataCompat.Builder putText(java.lang.String, java.lang.CharSequence);
+  }
+
+  public final class RatingCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.RatingCompat fromRating(java.lang.Object);
+    method public float getPercentRating();
+    method public java.lang.Object getRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.support.v4.media.RatingCompat newHeartRating(boolean);
+    method public static android.support.v4.media.RatingCompat newPercentageRating(float);
+    method public static android.support.v4.media.RatingCompat newStarRating(int, float);
+    method public static android.support.v4.media.RatingCompat newThumbRating(boolean);
+    method public static android.support.v4.media.RatingCompat newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat> CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_NONE = 0; // 0x0
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
+  public abstract class TransportController {
+    ctor public TransportController();
+    method public abstract int getBufferPercentage();
+    method public abstract long getCurrentPosition();
+    method public abstract long getDuration();
+    method public abstract int getTransportControlFlags();
+    method public abstract boolean isPlaying();
+    method public abstract void pausePlaying();
+    method public abstract void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public abstract void seekTo(long);
+    method public abstract void startPlaying();
+    method public abstract void stopPlaying();
+    method public abstract void unregisterStateListener(android.support.v4.media.TransportStateListener);
+  }
+
+  public class TransportMediator extends android.support.v4.media.TransportController {
+    ctor public TransportMediator(android.app.Activity, android.support.v4.media.TransportPerformer);
+    ctor public TransportMediator(android.view.View, android.support.v4.media.TransportPerformer);
+    method public void destroy();
+    method public boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public int getBufferPercentage();
+    method public long getCurrentPosition();
+    method public long getDuration();
+    method public java.lang.Object getRemoteControlClient();
+    method public int getTransportControlFlags();
+    method public boolean isPlaying();
+    method public void pausePlaying();
+    method public void refreshState();
+    method public void registerStateListener(android.support.v4.media.TransportStateListener);
+    method public void seekTo(long);
+    method public void startPlaying();
+    method public void stopPlaying();
+    method public void unregisterStateListener(android.support.v4.media.TransportStateListener);
+    field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+    field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+    field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+    field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+    field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+    field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+    field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+    field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+    field public static final int KEYCODE_MEDIA_PAUSE = 127; // 0x7f
+    field public static final int KEYCODE_MEDIA_PLAY = 126; // 0x7e
+    field public static final int KEYCODE_MEDIA_RECORD = 130; // 0x82
+  }
+
+  public abstract class TransportPerformer {
+    ctor public TransportPerformer();
+    method public void onAudioFocusChange(int);
+    method public int onGetBufferPercentage();
+    method public abstract long onGetCurrentPosition();
+    method public abstract long onGetDuration();
+    method public int onGetTransportControlFlags();
+    method public abstract boolean onIsPlaying();
+    method public boolean onMediaButtonDown(int, android.view.KeyEvent);
+    method public boolean onMediaButtonUp(int, android.view.KeyEvent);
+    method public abstract void onPause();
+    method public abstract void onSeekTo(long);
+    method public abstract void onStart();
+    method public abstract void onStop();
+  }
+
+  public class TransportStateListener {
+    ctor public TransportStateListener();
+    method public void onPlayingChanged(android.support.v4.media.TransportController);
+    method public void onTransportControlsChanged(android.support.v4.media.TransportController);
+  }
+
+  public abstract class VolumeProviderCompat {
+    ctor public VolumeProviderCompat(int, int, int);
+    method public final int getCurrentVolume();
+    method public final int getMaxVolume();
+    method public final int getVolumeControl();
+    method public java.lang.Object getVolumeProvider();
+    method public void onAdjustVolume(int);
+    method public void onSetVolumeTo(int);
+    method public void setCallback(android.support.v4.media.VolumeProviderCompat.Callback);
+    method public final void setCurrentVolume(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+  }
+
+  public static abstract class VolumeProviderCompat.Callback {
+    ctor public VolumeProviderCompat.Callback();
+    method public abstract void onVolumeChanged(android.support.v4.media.VolumeProviderCompat);
+  }
+
+}
+
+package android.support.v4.media.session {
+
+  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+    ctor public MediaButtonReceiver();
+    method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
+    method public void onReceive(android.content.Context, android.content.Intent);
+  }
+
+  public final class MediaControllerCompat {
+    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
+    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
+    method public void adjustVolume(int, int);
+    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+    method public android.os.Bundle getExtras();
+    method public long getFlags();
+    method public java.lang.Object getMediaController();
+    method public android.support.v4.media.MediaMetadataCompat getMetadata();
+    method public java.lang.String getPackageName();
+    method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo getPlaybackInfo();
+    method public android.support.v4.media.session.PlaybackStateCompat getPlaybackState();
+    method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> getQueue();
+    method public java.lang.CharSequence getQueueTitle();
+    method public int getRatingType();
+    method public android.app.PendingIntent getSessionActivity();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public android.support.v4.media.session.MediaControllerCompat.TransportControls getTransportControls();
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
+    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void setVolumeTo(int, int);
+    method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+  }
+
+  public static abstract class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+    ctor public MediaControllerCompat.Callback();
+    method public void binderDied();
+    method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo);
+    method public void onExtrasChanged(android.os.Bundle);
+    method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat);
+    method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat);
+    method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+    method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onSessionDestroyed();
+    method public void onSessionEvent(java.lang.String, android.os.Bundle);
+  }
+
+  public static final class MediaControllerCompat.PlaybackInfo {
+    method public int getAudioStream();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getPlaybackType();
+    method public int getVolumeControl();
+    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+  }
+
+  public static abstract class MediaControllerCompat.TransportControls {
+    method public abstract void fastForward();
+    method public abstract void pause();
+    method public abstract void play();
+    method public abstract void playFromMediaId(java.lang.String, android.os.Bundle);
+    method public abstract void playFromSearch(java.lang.String, android.os.Bundle);
+    method public abstract void playFromUri(android.net.Uri, android.os.Bundle);
+    method public abstract void rewind();
+    method public abstract void seekTo(long);
+    method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction, android.os.Bundle);
+    method public abstract void sendCustomAction(java.lang.String, android.os.Bundle);
+    method public abstract void setRating(android.support.v4.media.RatingCompat);
+    method public abstract void skipToNext();
+    method public abstract void skipToPrevious();
+    method public abstract void skipToQueueItem(long);
+    method public abstract void stop();
+  }
+
+  public class MediaSessionCompat {
+    ctor public MediaSessionCompat(android.content.Context, java.lang.String);
+    ctor public MediaSessionCompat(android.content.Context, java.lang.String, android.content.ComponentName, android.app.PendingIntent);
+    method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+    method public android.support.v4.media.session.MediaControllerCompat getController();
+    method public java.lang.Object getMediaSession();
+    method public java.lang.Object getRemoteControlClient();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isActive();
+    method public static android.support.v4.media.session.MediaSessionCompat obtain(android.content.Context, java.lang.Object);
+    method public void release();
+    method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+    method public void sendSessionEvent(java.lang.String, android.os.Bundle);
+    method public void setActive(boolean);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback, android.os.Handler);
+    method public void setExtras(android.os.Bundle);
+    method public void setFlags(int);
+    method public void setMediaButtonReceiver(android.app.PendingIntent);
+    method public void setMetadata(android.support.v4.media.MediaMetadataCompat);
+    method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat);
+    method public void setPlaybackToLocal(int);
+    method public void setPlaybackToRemote(android.support.v4.media.VolumeProviderCompat);
+    method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+    method public void setQueueTitle(java.lang.CharSequence);
+    method public void setRatingType(int);
+    method public void setSessionActivity(android.app.PendingIntent);
+    field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+  }
+
+  public static abstract class MediaSessionCompat.Callback {
+    ctor public MediaSessionCompat.Callback();
+    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void onCustomAction(java.lang.String, android.os.Bundle);
+    method public void onFastForward();
+    method public boolean onMediaButtonEvent(android.content.Intent);
+    method public void onPause();
+    method public void onPlay();
+    method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
+    method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+    method public void onRewind();
+    method public void onSeekTo(long);
+    method public void onSetRating(android.support.v4.media.RatingCompat);
+    method public void onSkipToNext();
+    method public void onSkipToPrevious();
+    method public void onSkipToQueueItem(long);
+    method public void onStop();
+  }
+
+  public static abstract interface MediaSessionCompat.OnActiveChangeListener {
+    method public abstract void onActiveChanged();
+  }
+
+  public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+    ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat, long);
+    method public int describeContents();
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public long getQueueId();
+    method public java.lang.Object getQueueItem();
+    method public static android.support.v4.media.session.MediaSessionCompat.QueueItem obtain(java.lang.Object);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem> CREATOR;
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
+  }
+
+  public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.Token fromToken(java.lang.Object);
+    method public java.lang.Object getToken();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token> CREATOR;
+  }
+
+  public class ParcelableVolumeInfo implements android.os.Parcelable {
+    ctor public ParcelableVolumeInfo(int, int, int, int, int);
+    ctor public ParcelableVolumeInfo(android.os.Parcel);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo> CREATOR;
+    field public int audioStream;
+    field public int controlType;
+    field public int currentVolume;
+    field public int maxVolume;
+    field public int volumeType;
+  }
+
+  public final class PlaybackStateCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat fromPlaybackState(java.lang.Object);
+    method public long getActions();
+    method public long getActiveQueueItemId();
+    method public long getBufferedPosition();
+    method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction> getCustomActions();
+    method public java.lang.CharSequence getErrorMessage();
+    method public android.os.Bundle getExtras();
+    method public long getLastPositionUpdateTime();
+    method public float getPlaybackSpeed();
+    method public java.lang.Object getPlaybackState();
+    method public long getPosition();
+    method public int getState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+    field public static final long ACTION_PAUSE = 2L; // 0x2L
+    field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+    field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+    field public static final long ACTION_REWIND = 8L; // 0x8L
+    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+    field public static final long ACTION_STOP = 1L; // 0x1L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat> CREATOR;
+    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int STATE_BUFFERING = 6; // 0x6
+    field public static final int STATE_CONNECTING = 8; // 0x8
+    field public static final int STATE_ERROR = 7; // 0x7
+    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_PAUSED = 2; // 0x2
+    field public static final int STATE_PLAYING = 3; // 0x3
+    field public static final int STATE_REWINDING = 5; // 0x5
+    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  public static final class PlaybackStateCompat.Builder {
+    ctor public PlaybackStateCompat.Builder();
+    ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(java.lang.String, java.lang.String, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction);
+    method public android.support.v4.media.session.PlaybackStateCompat build();
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActions(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActiveQueueItemId(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setBufferedPosition(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(java.lang.CharSequence);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setExtras(android.os.Bundle);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float, long);
+  }
+
+  public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction fromCustomAction(java.lang.Object);
+    method public java.lang.String getAction();
+    method public java.lang.Object getCustomAction();
+    method public android.os.Bundle getExtras();
+    method public int getIcon();
+    method public java.lang.CharSequence getName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction> CREATOR;
+  }
+
+  public static final class PlaybackStateCompat.CustomAction.Builder {
+    ctor public PlaybackStateCompat.CustomAction.Builder(java.lang.String, java.lang.CharSequence, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction build();
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder setExtras(android.os.Bundle);
+  }
+
+}
+
+package android.support.v4.net {
+
+  public class ConnectivityManagerCompat {
+    ctor public ConnectivityManagerCompat();
+    method public static android.net.NetworkInfo getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+    method public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+  }
+
+  public class TrafficStatsCompat {
+    ctor public TrafficStatsCompat();
+    method public static void clearThreadStatsTag();
+    method public static int getThreadStatsTag();
+    method public static void incrementOperationCount(int);
+    method public static void incrementOperationCount(int, int);
+    method public static void setThreadStatsTag(int);
+    method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
+    method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
+  }
+
+}
+
+package android.support.v4.os {
+
+  public class AsyncTaskCompat {
+    ctor public AsyncTaskCompat();
+    method public static android.os.AsyncTask<Params, Progress, Result> executeParallel(android.os.AsyncTask<Params, Progress, Result>, Params...);
+  }
+
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
+    method public void cancel();
+    method public java.lang.Object getCancellationSignalObject();
+    method public boolean isCanceled();
+    method public void setOnCancelListener(android.support.v4.os.CancellationSignal.OnCancelListener);
+    method public void throwIfCanceled();
+  }
+
+  public static abstract interface CancellationSignal.OnCancelListener {
+    method public abstract void onCancel();
+  }
+
+  public class EnvironmentCompat {
+    ctor public EnvironmentCompat();
+    method public static java.lang.String getStorageState(java.io.File);
+    field public static final java.lang.String MEDIA_UNKNOWN = "unknown";
+  }
+
+  public class OperationCanceledException extends java.lang.RuntimeException {
+    ctor public OperationCanceledException();
+    ctor public OperationCanceledException(java.lang.String);
+  }
+
+  public class ParcelableCompat {
+    ctor public ParcelableCompat();
+    method public static android.os.Parcelable.Creator<T> newCreator(android.support.v4.os.ParcelableCompatCreatorCallbacks<T>);
+  }
+
+  public abstract interface ParcelableCompatCreatorCallbacks {
+    method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
+    method public abstract T[] newArray(int);
+  }
+
+  public class TraceCompat {
+    ctor public TraceCompat();
+    method public static void beginSection(java.lang.String);
+    method public static void endSection();
+  }
+
+}
+
+package android.support.v4.print {
+
+  public final class PrintHelper {
+    ctor public PrintHelper(android.content.Context);
+    method public int getColorMode();
+    method public int getOrientation();
+    method public int getScaleMode();
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap);
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap, android.support.v4.print.PrintHelper.OnPrintFinishCallback);
+    method public void printBitmap(java.lang.String, android.net.Uri) throws java.io.FileNotFoundException;
+    method public void printBitmap(java.lang.String, android.net.Uri, android.support.v4.print.PrintHelper.OnPrintFinishCallback) throws java.io.FileNotFoundException;
+    method public void setColorMode(int);
+    method public void setOrientation(int);
+    method public void setScaleMode(int);
+    method public static boolean systemSupportsPrint();
+    field public static final int COLOR_MODE_COLOR = 2; // 0x2
+    field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
+    field public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
+    field public static final int ORIENTATION_PORTRAIT = 2; // 0x2
+    field public static final int SCALE_MODE_FILL = 2; // 0x2
+    field public static final int SCALE_MODE_FIT = 1; // 0x1
+  }
+
+  public static abstract interface PrintHelper.OnPrintFinishCallback {
+    method public abstract void onFinish();
+  }
+
+}
+
+package android.support.v4.provider {
+
+  public abstract class DocumentFile {
+    method public abstract boolean canRead();
+    method public abstract boolean canWrite();
+    method public abstract android.support.v4.provider.DocumentFile createDirectory(java.lang.String);
+    method public abstract android.support.v4.provider.DocumentFile createFile(java.lang.String, java.lang.String);
+    method public abstract boolean delete();
+    method public abstract boolean exists();
+    method public android.support.v4.provider.DocumentFile findFile(java.lang.String);
+    method public static android.support.v4.provider.DocumentFile fromFile(java.io.File);
+    method public static android.support.v4.provider.DocumentFile fromSingleUri(android.content.Context, android.net.Uri);
+    method public static android.support.v4.provider.DocumentFile fromTreeUri(android.content.Context, android.net.Uri);
+    method public abstract java.lang.String getName();
+    method public android.support.v4.provider.DocumentFile getParentFile();
+    method public abstract java.lang.String getType();
+    method public abstract android.net.Uri getUri();
+    method public abstract boolean isDirectory();
+    method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public abstract boolean isFile();
+    method public abstract long lastModified();
+    method public abstract long length();
+    method public abstract android.support.v4.provider.DocumentFile[] listFiles();
+    method public abstract boolean renameTo(java.lang.String);
+  }
+
+}
+
+package android.support.v4.text {
+
+  public final class BidiFormatter {
+    method public static android.support.v4.text.BidiFormatter getInstance();
+    method public static android.support.v4.text.BidiFormatter getInstance(boolean);
+    method public static android.support.v4.text.BidiFormatter getInstance(java.util.Locale);
+    method public boolean getStereoReset();
+    method public boolean isRtl(java.lang.String);
+    method public boolean isRtlContext();
+    method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat);
+    method public java.lang.String unicodeWrap(java.lang.String, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale);
+    method public android.support.v4.text.BidiFormatter build();
+    method public android.support.v4.text.BidiFormatter.Builder setTextDirectionHeuristic(android.support.v4.text.TextDirectionHeuristicCompat);
+    method public android.support.v4.text.BidiFormatter.Builder stereoReset(boolean);
+  }
+
+  public class ICUCompat {
+    ctor public ICUCompat();
+    method public static java.lang.String maximizeAndGetScript(java.util.Locale);
+  }
+
+  public abstract interface TextDirectionHeuristicCompat {
+    method public abstract boolean isRtl(char[], int, int);
+    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+  }
+
+  public class TextDirectionHeuristicsCompat {
+    ctor public TextDirectionHeuristicsCompat();
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat ANYRTL_LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_RTL;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat LOCALE;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat LTR;
+    field public static final android.support.v4.text.TextDirectionHeuristicCompat RTL;
+  }
+
+  public class TextUtilsCompat {
+    ctor public TextUtilsCompat();
+    method public static int getLayoutDirectionFromLocale(java.util.Locale);
+    method public static java.lang.String htmlEncode(java.lang.String);
+    field public static final java.util.Locale ROOT;
+  }
+
+}
+
+package android.support.v4.util {
+
+  public class ArrayMap extends android.support.v4.util.SimpleArrayMap implements java.util.Map {
+    ctor public ArrayMap();
+    ctor public ArrayMap(int);
+    ctor public ArrayMap(android.support.v4.util.SimpleArrayMap);
+    method public boolean containsAll(java.util.Collection<?>);
+    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public java.util.Set<K> keySet();
+    method public void putAll(java.util.Map<? extends K, ? extends V>);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public java.util.Collection<V> values();
+  }
+
+  public class AtomicFile {
+    ctor public AtomicFile(java.io.File);
+    method public void delete();
+    method public void failWrite(java.io.FileOutputStream);
+    method public void finishWrite(java.io.FileOutputStream);
+    method public java.io.File getBaseFile();
+    method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+    method public byte[] readFully() throws java.io.IOException;
+    method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+  }
+
+  public final class CircularArray {
+    ctor public CircularArray();
+    ctor public CircularArray(int);
+    method public void addFirst(E);
+    method public void addLast(E);
+    method public void clear();
+    method public E get(int);
+    method public E getFirst();
+    method public E getLast();
+    method public boolean isEmpty();
+    method public E popFirst();
+    method public E popLast();
+    method public void removeFromEnd(int);
+    method public void removeFromStart(int);
+    method public int size();
+  }
+
+  public final class CircularIntArray {
+    ctor public CircularIntArray();
+    ctor public CircularIntArray(int);
+    method public void addFirst(int);
+    method public void addLast(int);
+    method public void clear();
+    method public int get(int);
+    method public int getFirst();
+    method public int getLast();
+    method public boolean isEmpty();
+    method public int popFirst();
+    method public int popLast();
+    method public void removeFromEnd(int);
+    method public void removeFromStart(int);
+    method public int size();
+  }
+
+  public class LongSparseArray {
+    ctor public LongSparseArray();
+    ctor public LongSparseArray(int);
+    method public void append(long, E);
+    method public void clear();
+    method public android.support.v4.util.LongSparseArray<E> clone();
+    method public void delete(long);
+    method public E get(long);
+    method public E get(long, E);
+    method public int indexOfKey(long);
+    method public int indexOfValue(E);
+    method public long keyAt(int);
+    method public void put(long, E);
+    method public void remove(long);
+    method public void removeAt(int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+  public class LruCache {
+    ctor public LruCache(int);
+    method protected V create(K);
+    method public final synchronized int createCount();
+    method protected void entryRemoved(boolean, K, V, V);
+    method public final void evictAll();
+    method public final synchronized int evictionCount();
+    method public final V get(K);
+    method public final synchronized int hitCount();
+    method public final synchronized int maxSize();
+    method public final synchronized int missCount();
+    method public final V put(K, V);
+    method public final synchronized int putCount();
+    method public final V remove(K);
+    method public void resize(int);
+    method public final synchronized int size();
+    method protected int sizeOf(K, V);
+    method public final synchronized java.util.Map<K, V> snapshot();
+    method public final synchronized java.lang.String toString();
+    method public void trimToSize(int);
+  }
+
+  public class Pair {
+    ctor public Pair(F, S);
+    method public static android.support.v4.util.Pair<A, B> create(A, B);
+    field public final F first;
+    field public final S second;
+  }
+
+  public final class Pools {
+  }
+
+  public static abstract interface Pools.Pool {
+    method public abstract T acquire();
+    method public abstract boolean release(T);
+  }
+
+  public static class Pools.SimplePool implements android.support.v4.util.Pools.Pool {
+    ctor public Pools.SimplePool(int);
+    method public T acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SynchronizedPool extends android.support.v4.util.Pools.SimplePool {
+    ctor public Pools.SynchronizedPool(int);
+  }
+
+  public class SimpleArrayMap {
+    ctor public SimpleArrayMap();
+    ctor public SimpleArrayMap(int);
+    ctor public SimpleArrayMap(android.support.v4.util.SimpleArrayMap);
+    method public void clear();
+    method public boolean containsKey(java.lang.Object);
+    method public boolean containsValue(java.lang.Object);
+    method public void ensureCapacity(int);
+    method public V get(java.lang.Object);
+    method public int indexOfKey(java.lang.Object);
+    method public boolean isEmpty();
+    method public K keyAt(int);
+    method public V put(K, V);
+    method public void putAll(android.support.v4.util.SimpleArrayMap<? extends K, ? extends V>);
+    method public V remove(java.lang.Object);
+    method public V removeAt(int);
+    method public V setValueAt(int, V);
+    method public int size();
+    method public V valueAt(int);
+  }
+
+  public class SparseArrayCompat {
+    ctor public SparseArrayCompat();
+    ctor public SparseArrayCompat(int);
+    method public void append(int, E);
+    method public void clear();
+    method public android.support.v4.util.SparseArrayCompat<E> clone();
+    method public void delete(int);
+    method public E get(int);
+    method public E get(int, E);
+    method public int indexOfKey(int);
+    method public int indexOfValue(E);
+    method public int keyAt(int);
+    method public void put(int, E);
+    method public void remove(int);
+    method public void removeAt(int);
+    method public void removeAtRange(int, int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+}
+
+package android.support.v4.view {
+
+  public class AccessibilityDelegateCompat {
+    ctor public AccessibilityDelegateCompat();
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+    method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+    method public void sendAccessibilityEvent(android.view.View, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
+  public abstract class ActionProvider {
+    ctor public ActionProvider(android.content.Context);
+    method public android.content.Context getContext();
+    method public boolean hasSubMenu();
+    method public boolean isVisible();
+    method public abstract android.view.View onCreateActionView();
+    method public android.view.View onCreateActionView(android.view.MenuItem);
+    method public boolean onPerformDefaultAction();
+    method public void onPrepareSubMenu(android.view.SubMenu);
+    method public boolean overridesItemVisibility();
+    method public void refreshVisibility();
+    method public void setVisibilityListener(android.support.v4.view.ActionProvider.VisibilityListener);
+  }
+
+  public static abstract interface ActionProvider.VisibilityListener {
+    method public abstract void onActionProviderVisibilityChanged(boolean);
+  }
+
+  public class GestureDetectorCompat {
+    ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+    ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler);
+    method public boolean isLongpressEnabled();
+    method public boolean onTouchEvent(android.view.MotionEvent);
+    method public void setIsLongpressEnabled(boolean);
+    method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
+  }
+
+  public class GravityCompat {
+    ctor public GravityCompat();
+    method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+    method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+    method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+    method public static int getAbsoluteGravity(int, int);
+    field public static final int END = 8388613; // 0x800005
+    field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+    field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+    field public static final int START = 8388611; // 0x800003
+  }
+
+  public class InputDeviceCompat {
+    ctor public InputDeviceCompat();
+    field public static final int SOURCE_ANY = -256; // 0xffffff00
+    field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+    field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+    field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+    field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+    field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+    field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+    field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+    field public static final int SOURCE_DPAD = 513; // 0x201
+    field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+    field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+    field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+    field public static final int SOURCE_KEYBOARD = 257; // 0x101
+    field public static final int SOURCE_MOUSE = 8194; // 0x2002
+    field public static final int SOURCE_STYLUS = 16386; // 0x4002
+    field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+    field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+    field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+    field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+    field public static final int SOURCE_UNKNOWN = 0; // 0x0
+  }
+
+  public class KeyEventCompat {
+    ctor public KeyEventCompat();
+    method public static boolean dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object);
+    method public static java.lang.Object getKeyDispatcherState(android.view.View);
+    method public static boolean hasModifiers(android.view.KeyEvent, int);
+    method public static boolean hasNoModifiers(android.view.KeyEvent);
+    method public static boolean isTracking(android.view.KeyEvent);
+    method public static boolean metaStateHasModifiers(int, int);
+    method public static boolean metaStateHasNoModifiers(int);
+    method public static int normalizeMetaState(int);
+    method public static void startTracking(android.view.KeyEvent);
+  }
+
+  public class LayoutInflaterCompat {
+    method public static void setFactory(android.view.LayoutInflater, android.support.v4.view.LayoutInflaterFactory);
+  }
+
+  public abstract interface LayoutInflaterFactory {
+    method public abstract android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+  }
+
+  public class MarginLayoutParamsCompat {
+    ctor public MarginLayoutParamsCompat();
+    method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+    method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+    method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+    method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+    method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+    method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+  }
+
+  public class MenuCompat {
+    ctor public MenuCompat();
+    method public static deprecated void setShowAsAction(android.view.MenuItem, int);
+  }
+
+  public class MenuItemCompat {
+    ctor public MenuItemCompat();
+    method public static boolean collapseActionView(android.view.MenuItem);
+    method public static boolean expandActionView(android.view.MenuItem);
+    method public static android.support.v4.view.ActionProvider getActionProvider(android.view.MenuItem);
+    method public static android.view.View getActionView(android.view.MenuItem);
+    method public static boolean isActionViewExpanded(android.view.MenuItem);
+    method public static android.view.MenuItem setActionProvider(android.view.MenuItem, android.support.v4.view.ActionProvider);
+    method public static android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
+    method public static android.view.MenuItem setActionView(android.view.MenuItem, int);
+    method public static android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
+    method public static void setShowAsAction(android.view.MenuItem, int);
+    field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+  }
+
+  public static abstract interface MenuItemCompat.OnActionExpandListener {
+    method public abstract boolean onMenuItemActionCollapse(android.view.MenuItem);
+    method public abstract boolean onMenuItemActionExpand(android.view.MenuItem);
+  }
+
+  public class MotionEventCompat {
+    ctor public MotionEventCompat();
+    method public static int findPointerIndex(android.view.MotionEvent, int);
+    method public static int getActionIndex(android.view.MotionEvent);
+    method public static int getActionMasked(android.view.MotionEvent);
+    method public static float getAxisValue(android.view.MotionEvent, int);
+    method public static float getAxisValue(android.view.MotionEvent, int, int);
+    method public static int getPointerCount(android.view.MotionEvent);
+    method public static int getPointerId(android.view.MotionEvent, int);
+    method public static int getSource(android.view.MotionEvent);
+    method public static float getX(android.view.MotionEvent, int);
+    method public static float getY(android.view.MotionEvent, int);
+    field public static final int ACTION_HOVER_ENTER = 9; // 0x9
+    field public static final int ACTION_HOVER_EXIT = 10; // 0xa
+    field public static final int ACTION_HOVER_MOVE = 7; // 0x7
+    field public static final int ACTION_MASK = 255; // 0xff
+    field public static final int ACTION_POINTER_DOWN = 5; // 0x5
+    field public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+    field public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+    field public static final int ACTION_POINTER_UP = 6; // 0x6
+    field public static final int ACTION_SCROLL = 8; // 0x8
+    field public static final int AXIS_BRAKE = 23; // 0x17
+    field public static final int AXIS_DISTANCE = 24; // 0x18
+    field public static final int AXIS_GAS = 22; // 0x16
+    field public static final int AXIS_GENERIC_1 = 32; // 0x20
+    field public static final int AXIS_GENERIC_10 = 41; // 0x29
+    field public static final int AXIS_GENERIC_11 = 42; // 0x2a
+    field public static final int AXIS_GENERIC_12 = 43; // 0x2b
+    field public static final int AXIS_GENERIC_13 = 44; // 0x2c
+    field public static final int AXIS_GENERIC_14 = 45; // 0x2d
+    field public static final int AXIS_GENERIC_15 = 46; // 0x2e
+    field public static final int AXIS_GENERIC_16 = 47; // 0x2f
+    field public static final int AXIS_GENERIC_2 = 33; // 0x21
+    field public static final int AXIS_GENERIC_3 = 34; // 0x22
+    field public static final int AXIS_GENERIC_4 = 35; // 0x23
+    field public static final int AXIS_GENERIC_5 = 36; // 0x24
+    field public static final int AXIS_GENERIC_6 = 37; // 0x25
+    field public static final int AXIS_GENERIC_7 = 38; // 0x26
+    field public static final int AXIS_GENERIC_8 = 39; // 0x27
+    field public static final int AXIS_GENERIC_9 = 40; // 0x28
+    field public static final int AXIS_HAT_X = 15; // 0xf
+    field public static final int AXIS_HAT_Y = 16; // 0x10
+    field public static final int AXIS_HSCROLL = 10; // 0xa
+    field public static final int AXIS_LTRIGGER = 17; // 0x11
+    field public static final int AXIS_ORIENTATION = 8; // 0x8
+    field public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RTRIGGER = 18; // 0x12
+    field public static final int AXIS_RUDDER = 20; // 0x14
+    field public static final int AXIS_RX = 12; // 0xc
+    field public static final int AXIS_RY = 13; // 0xd
+    field public static final int AXIS_RZ = 14; // 0xe
+    field public static final int AXIS_SIZE = 3; // 0x3
+    field public static final int AXIS_THROTTLE = 19; // 0x13
+    field public static final int AXIS_TILT = 25; // 0x19
+    field public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+    field public static final int AXIS_TOOL_MINOR = 7; // 0x7
+    field public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+    field public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+    field public static final int AXIS_VSCROLL = 9; // 0x9
+    field public static final int AXIS_WHEEL = 21; // 0x15
+    field public static final int AXIS_X = 0; // 0x0
+    field public static final int AXIS_Y = 1; // 0x1
+    field public static final int AXIS_Z = 11; // 0xb
+  }
+
+  public abstract interface NestedScrollingChild {
+    method public abstract boolean dispatchNestedFling(float, float, boolean);
+    method public abstract boolean dispatchNestedPreFling(float, float);
+    method public abstract boolean dispatchNestedPreScroll(int, int, int[], int[]);
+    method public abstract boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public abstract boolean hasNestedScrollingParent();
+    method public abstract boolean isNestedScrollingEnabled();
+    method public abstract void setNestedScrollingEnabled(boolean);
+    method public abstract boolean startNestedScroll(int);
+    method public abstract void stopNestedScroll();
+  }
+
+  public class NestedScrollingChildHelper {
+    ctor public NestedScrollingChildHelper(android.view.View);
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public boolean hasNestedScrollingParent();
+    method public boolean isNestedScrollingEnabled();
+    method public void onDetachedFromWindow();
+    method public void onStopNestedScroll(android.view.View);
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public void stopNestedScroll();
+  }
+
+  public abstract interface NestedScrollingParent {
+    method public abstract int getNestedScrollAxes();
+    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
+    method public abstract boolean onNestedPreFling(android.view.View, float, float);
+    method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
+    method public abstract void onNestedScroll(android.view.View, int, int, int, int);
+    method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public abstract boolean onStartNestedScroll(android.view.View, android.view.View, int);
+    method public abstract void onStopNestedScroll(android.view.View);
+  }
+
+  public class NestedScrollingParentHelper {
+    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+    method public int getNestedScrollAxes();
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.view.View);
+  }
+
+  public abstract interface OnApplyWindowInsetsListener {
+    method public abstract android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+  }
+
+  public abstract class PagerAdapter {
+    ctor public PagerAdapter();
+    method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
+    method public void finishUpdate(android.view.ViewGroup);
+    method public deprecated void finishUpdate(android.view.View);
+    method public abstract int getCount();
+    method public int getItemPosition(java.lang.Object);
+    method public java.lang.CharSequence getPageTitle(int);
+    method public float getPageWidth(int);
+    method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
+    method public deprecated java.lang.Object instantiateItem(android.view.View, int);
+    method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
+    method public void notifyDataSetChanged();
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+    method public android.os.Parcelable saveState();
+    method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
+    method public void startUpdate(android.view.ViewGroup);
+    method public deprecated void startUpdate(android.view.View);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
+    field public static final int POSITION_NONE = -2; // 0xfffffffe
+    field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
+  }
+
+  public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
+    ctor public PagerTabStrip(android.content.Context);
+    ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
+    method public boolean getDrawFullUnderline();
+    method public int getTabIndicatorColor();
+    method public void setDrawFullUnderline(boolean);
+    method public void setTabIndicatorColor(int);
+    method public void setTabIndicatorColorResource(int);
+  }
+
+  public class PagerTitleStrip extends android.view.ViewGroup {
+    ctor public PagerTitleStrip(android.content.Context);
+    ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
+    method public int getTextSpacing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setGravity(int);
+    method public void setNonPrimaryAlpha(float);
+    method public void setTextColor(int);
+    method public void setTextSize(int, float);
+    method public void setTextSpacing(int);
+  }
+
+  public class ScaleGestureDetectorCompat {
+    method public static boolean isQuickScaleEnabled(java.lang.Object);
+    method public static void setQuickScaleEnabled(java.lang.Object, boolean);
+  }
+
+  public abstract interface ScrollingView {
+    method public abstract int computeHorizontalScrollExtent();
+    method public abstract int computeHorizontalScrollOffset();
+    method public abstract int computeHorizontalScrollRange();
+    method public abstract int computeVerticalScrollExtent();
+    method public abstract int computeVerticalScrollOffset();
+    method public abstract int computeVerticalScrollRange();
+  }
+
+  public class VelocityTrackerCompat {
+    ctor public VelocityTrackerCompat();
+    method public static float getXVelocity(android.view.VelocityTracker, int);
+    method public static float getYVelocity(android.view.VelocityTracker, int);
+  }
+
+  public class ViewCompat {
+    ctor public ViewCompat();
+    method public static android.support.v4.view.ViewPropertyAnimatorCompat animate(android.view.View);
+    method public static boolean canScrollHorizontally(android.view.View, int);
+    method public static boolean canScrollVertically(android.view.View, int);
+    method public static int combineMeasuredStates(int, int);
+    method public static android.support.v4.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+    method public static void dispatchFinishTemporaryDetach(android.view.View);
+    method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+    method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[], int[]);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]);
+    method public static void dispatchStartTemporaryDetach(android.view.View);
+    method public static int getAccessibilityLiveRegion(android.view.View);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+    method public static float getAlpha(android.view.View);
+    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 float getElevation(android.view.View);
+    method public static boolean getFitsSystemWindows(android.view.View);
+    method public static int getImportantForAccessibility(android.view.View);
+    method public static int getLabelFor(android.view.View);
+    method public static int getLayerType(android.view.View);
+    method public static int getLayoutDirection(android.view.View);
+    method public static int getMeasuredHeightAndState(android.view.View);
+    method public static int getMeasuredState(android.view.View);
+    method public static int getMeasuredWidthAndState(android.view.View);
+    method public static int getMinimumHeight(android.view.View);
+    method public static int getMinimumWidth(android.view.View);
+    method public static int getOverScrollMode(android.view.View);
+    method public static int getPaddingEnd(android.view.View);
+    method public static int getPaddingStart(android.view.View);
+    method public static android.view.ViewParent getParentForAccessibility(android.view.View);
+    method public static float getPivotX(android.view.View);
+    method public static float getPivotY(android.view.View);
+    method public static float getRotation(android.view.View);
+    method public static float getRotationX(android.view.View);
+    method public static float getRotationY(android.view.View);
+    method public static float getScaleX(android.view.View);
+    method public static float getScaleY(android.view.View);
+    method public static int getScrollIndicators(android.view.View);
+    method public static java.lang.String getTransitionName(android.view.View);
+    method public static float getTranslationX(android.view.View);
+    method public static float getTranslationY(android.view.View);
+    method public static float getTranslationZ(android.view.View);
+    method public static int getWindowSystemUiVisibility(android.view.View);
+    method public static float getX(android.view.View);
+    method public static float getY(android.view.View);
+    method public static float getZ(android.view.View);
+    method public static boolean hasAccessibilityDelegate(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View);
+    method public static boolean hasOnClickListeners(android.view.View);
+    method public static boolean hasOverlappingRendering(android.view.View);
+    method public static boolean hasTransientState(android.view.View);
+    method public static boolean isAttachedToWindow(android.view.View);
+    method public static boolean isLaidOut(android.view.View);
+    method public static boolean isNestedScrollingEnabled(android.view.View);
+    method public static boolean isOpaque(android.view.View);
+    method public static boolean isPaddingRelative(android.view.View);
+    method public static void jumpDrawablesToCurrentState(android.view.View);
+    method public static void offsetLeftAndRight(android.view.View, int);
+    method public static void offsetTopAndBottom(android.view.View, int);
+    method public static android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+    method public static void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public static void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+    method public static void postInvalidateOnAnimation(android.view.View);
+    method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method public static void postOnAnimation(android.view.View, java.lang.Runnable);
+    method public static void postOnAnimationDelayed(android.view.View, java.lang.Runnable, long);
+    method public static void requestApplyInsets(android.view.View);
+    method public static int resolveSizeAndState(int, int, int);
+    method public static void setAccessibilityDelegate(android.view.View, android.support.v4.view.AccessibilityDelegateCompat);
+    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 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);
+    method public static void setClipBounds(android.view.View, android.graphics.Rect);
+    method public static void setElevation(android.view.View, float);
+    method public static void setFitsSystemWindows(android.view.View, boolean);
+    method public static void setHasTransientState(android.view.View, boolean);
+    method public static void setImportantForAccessibility(android.view.View, int);
+    method public static void setLabelFor(android.view.View, int);
+    method public static void setLayerPaint(android.view.View, android.graphics.Paint);
+    method public static void setLayerType(android.view.View, int, android.graphics.Paint);
+    method public static void setLayoutDirection(android.view.View, int);
+    method public static void setNestedScrollingEnabled(android.view.View, boolean);
+    method public static void setOnApplyWindowInsetsListener(android.view.View, android.support.v4.view.OnApplyWindowInsetsListener);
+    method public static void setOverScrollMode(android.view.View, int);
+    method public static void setPaddingRelative(android.view.View, int, int, int, int);
+    method public static void setPivotX(android.view.View, float);
+    method public static void setPivotY(android.view.View, float);
+    method public static void setRotation(android.view.View, float);
+    method public static void setRotationX(android.view.View, float);
+    method public static void setRotationY(android.view.View, float);
+    method public static void setSaveFromParentEnabled(android.view.View, boolean);
+    method public static void setScaleX(android.view.View, float);
+    method public static void setScaleY(android.view.View, float);
+    method public static void setScrollIndicators(android.view.View, int);
+    method public static void setScrollIndicators(android.view.View, int, int);
+    method public static void setTransitionName(android.view.View, java.lang.String);
+    method public static void setTranslationX(android.view.View, float);
+    method public static void setTranslationY(android.view.View, float);
+    method public static void setTranslationZ(android.view.View, float);
+    method public static void setX(android.view.View, float);
+    method public static void setY(android.view.View, float);
+    method public static boolean startNestedScroll(android.view.View, int);
+    method public static void stopNestedScroll(android.view.View);
+    field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+    field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+    field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+    field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+    field public static final int LAYER_TYPE_NONE = 0; // 0x0
+    field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+    field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+    field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+    field public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+    field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+    field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+    field public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+    field public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+    field public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+    field public static final int OVER_SCROLL_NEVER = 2; // 0x2
+    field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+    field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+    field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+    field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+    field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+    field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+    field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+  }
+
+  public class ViewConfigurationCompat {
+    ctor public ViewConfigurationCompat();
+    method public static int getScaledPagingTouchSlop(android.view.ViewConfiguration);
+    method public static boolean hasPermanentMenuKey(android.view.ViewConfiguration);
+  }
+
+  public class ViewGroupCompat {
+    method public static int getLayoutMode(android.view.ViewGroup);
+    method public static int getNestedScrollAxes(android.view.ViewGroup);
+    method public static boolean isTransitionGroup(android.view.ViewGroup);
+    method public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public static void setLayoutMode(android.view.ViewGroup, int);
+    method public static void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
+    method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+    field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+    field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+  }
+
+  public class ViewPager extends android.view.ViewGroup {
+    ctor public ViewPager(android.content.Context);
+    ctor public ViewPager(android.content.Context, android.util.AttributeSet);
+    method public void addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public boolean arrowScroll(int);
+    method public boolean beginFakeDrag();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public void clearOnPageChangeListeners();
+    method public void endFakeDrag();
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fakeDragBy(float);
+    method public android.support.v4.view.PagerAdapter getAdapter();
+    method public int getCurrentItem();
+    method public int getOffscreenPageLimit();
+    method public int getPageMargin();
+    method public boolean isFakeDragging();
+    method protected void onLayout(boolean, int, int, int, int);
+    method protected void onPageScrolled(int, float, int);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void removeOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setAdapter(android.support.v4.view.PagerAdapter);
+    method public void setCurrentItem(int);
+    method public void setCurrentItem(int, boolean);
+    method public void setOffscreenPageLimit(int);
+    method public deprecated void setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setPageMargin(int);
+    method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
+    method public void setPageMarginDrawable(int);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+    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
+  }
+
+  public static class ViewPager.LayoutParams extends android.view.ViewGroup.LayoutParams {
+    ctor public ViewPager.LayoutParams();
+    ctor public ViewPager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public int gravity;
+    field public boolean isDecor;
+  }
+
+  public static abstract interface ViewPager.OnPageChangeListener {
+    method public abstract void onPageScrollStateChanged(int);
+    method public abstract void onPageScrolled(int, float, int);
+    method public abstract void onPageSelected(int);
+  }
+
+  public static abstract interface ViewPager.PageTransformer {
+    method public abstract void transformPage(android.view.View, float);
+  }
+
+  public static class ViewPager.SavedState extends android.view.View.BaseSavedState {
+    ctor public ViewPager.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.view.ViewPager.SavedState> CREATOR;
+  }
+
+  public static class ViewPager.SimpleOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+    ctor public ViewPager.SimpleOnPageChangeListener();
+    method public void onPageScrollStateChanged(int);
+    method public void onPageScrolled(int, float, int);
+    method public void onPageSelected(int);
+  }
+
+  public class ViewParentCompat {
+    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+    method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+    method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+    method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+    method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+    method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+    method public static boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
+  public class ViewPropertyAnimatorCompat {
+    method public android.support.v4.view.ViewPropertyAnimatorCompat alpha(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat alphaBy(float);
+    method public void cancel();
+    method public long getDuration();
+    method public android.view.animation.Interpolator getInterpolator();
+    method public long getStartDelay();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotation(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat rotationYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat scaleYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setDuration(long);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setListener(android.support.v4.view.ViewPropertyAnimatorListener);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setStartDelay(long);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat setUpdateListener(android.support.v4.view.ViewPropertyAnimatorUpdateListener);
+    method public void start();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationX(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationXBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationY(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationYBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationZ(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat translationZBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withEndAction(java.lang.Runnable);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withLayer();
+    method public android.support.v4.view.ViewPropertyAnimatorCompat withStartAction(java.lang.Runnable);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat x(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat xBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat y(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat yBy(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat z(float);
+    method public android.support.v4.view.ViewPropertyAnimatorCompat zBy(float);
+  }
+
+  public abstract interface ViewPropertyAnimatorListener {
+    method public abstract void onAnimationCancel(android.view.View);
+    method public abstract void onAnimationEnd(android.view.View);
+    method public abstract void onAnimationStart(android.view.View);
+  }
+
+  public class ViewPropertyAnimatorListenerAdapter implements android.support.v4.view.ViewPropertyAnimatorListener {
+    ctor public ViewPropertyAnimatorListenerAdapter();
+    method public void onAnimationCancel(android.view.View);
+    method public void onAnimationEnd(android.view.View);
+    method public void onAnimationStart(android.view.View);
+  }
+
+  public abstract interface ViewPropertyAnimatorUpdateListener {
+    method public abstract void onAnimationUpdate(android.view.View);
+  }
+
+  public class WindowCompat {
+    ctor public WindowCompat();
+    field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+    field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+  }
+
+  public class WindowInsetsCompat {
+    method public android.support.v4.view.WindowInsetsCompat consumeStableInsets();
+    method public android.support.v4.view.WindowInsetsCompat consumeSystemWindowInsets();
+    method public int getStableInsetBottom();
+    method public int getStableInsetLeft();
+    method public int getStableInsetRight();
+    method public int getStableInsetTop();
+    method public int getSystemWindowInsetBottom();
+    method public int getSystemWindowInsetLeft();
+    method public int getSystemWindowInsetRight();
+    method public int getSystemWindowInsetTop();
+    method public boolean hasInsets();
+    method public boolean hasStableInsets();
+    method public boolean hasSystemWindowInsets();
+    method public boolean isConsumed();
+    method public boolean isRound();
+    method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+    method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+  }
+
+}
+
+package android.support.v4.view.accessibility {
+
+  public class AccessibilityEventCompat {
+    method public static void appendRecord(android.view.accessibility.AccessibilityEvent, android.support.v4.view.accessibility.AccessibilityRecordCompat);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat asRecord(android.view.accessibility.AccessibilityEvent);
+    method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat getRecord(android.view.accessibility.AccessibilityEvent, int);
+    method public static int getRecordCount(android.view.accessibility.AccessibilityEvent);
+    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+    field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+    field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+    field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+    field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+    field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+    field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+    field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+    field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+    field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+    field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+    field public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+    field public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+    field public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+    field public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+    field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+    field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+  }
+
+  public class AccessibilityManagerCompat {
+    ctor public AccessibilityManagerCompat();
+    method public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat);
+    method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager, int);
+    method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager);
+    method public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager);
+    method public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat);
+  }
+
+  public static abstract class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat {
+    ctor public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+    method public abstract void onAccessibilityStateChanged(boolean);
+  }
+
+  public class AccessibilityNodeInfoCompat {
+    ctor public AccessibilityNodeInfoCompat(java.lang.Object);
+    method public void addAction(int);
+    method public void addAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+    method public void addChild(android.view.View);
+    method public void addChild(android.view.View, int);
+    method public boolean canOpenPopup();
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(java.lang.String);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat focusSearch(int);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat> getActionList();
+    method public int getActions();
+    method public void getBoundsInParent(android.graphics.Rect);
+    method public void getBoundsInScreen(android.graphics.Rect);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getChild(int);
+    method public int getChildCount();
+    method public java.lang.CharSequence getClassName();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat getCollectionInfo();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat getCollectionItemInfo();
+    method public java.lang.CharSequence getContentDescription();
+    method public java.lang.CharSequence getError();
+    method public android.os.Bundle getExtras();
+    method public java.lang.Object getInfo();
+    method public int getInputType();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabelFor();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabeledBy();
+    method public int getLiveRegion();
+    method public int getMaxTextLength();
+    method public int getMovementGranularities();
+    method public java.lang.CharSequence getPackageName();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getParent();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat getRangeInfo();
+    method public java.lang.CharSequence getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalAfter();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalBefore();
+    method public java.lang.String getViewIdResourceName();
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getWindow();
+    method public int getWindowId();
+    method public boolean isAccessibilityFocused();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isContentInvalid();
+    method public boolean isDismissable();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isLongClickable();
+    method public boolean isMultiLine();
+    method public boolean isPassword();
+    method public boolean isScrollable();
+    method public boolean isSelected();
+    method public boolean isVisibleToUser();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View, int);
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public boolean performAction(int);
+    method public boolean performAction(int, android.os.Bundle);
+    method public void recycle();
+    method public boolean refresh();
+    method public boolean removeAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+    method public boolean removeChild(android.view.View);
+    method public boolean removeChild(android.view.View, int);
+    method public void setAccessibilityFocused(boolean);
+    method public void setBoundsInParent(android.graphics.Rect);
+    method public void setBoundsInScreen(android.graphics.Rect);
+    method public void setCanOpenPopup(boolean);
+    method public void setCheckable(boolean);
+    method public void setChecked(boolean);
+    method public void setClassName(java.lang.CharSequence);
+    method public void setClickable(boolean);
+    method public void setCollectionInfo(java.lang.Object);
+    method public void setCollectionItemInfo(java.lang.Object);
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setContentInvalid(boolean);
+    method public void setDismissable(boolean);
+    method public void setEditable(boolean);
+    method public void setEnabled(boolean);
+    method public void setError(java.lang.CharSequence);
+    method public void setFocusable(boolean);
+    method public void setFocused(boolean);
+    method public void setInputType(int);
+    method public void setLabelFor(android.view.View);
+    method public void setLabelFor(android.view.View, int);
+    method public void setLabeledBy(android.view.View);
+    method public void setLabeledBy(android.view.View, int);
+    method public void setLiveRegion(int);
+    method public void setLongClickable(boolean);
+    method public void setMaxTextLength(int);
+    method public void setMovementGranularities(int);
+    method public void setMultiLine(boolean);
+    method public void setPackageName(java.lang.CharSequence);
+    method public void setParent(android.view.View);
+    method public void setParent(android.view.View, int);
+    method public void setPassword(boolean);
+    method public void setRangeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat);
+    method public void setScrollable(boolean);
+    method public void setSelected(boolean);
+    method public void setSource(android.view.View);
+    method public void setSource(android.view.View, int);
+    method public void setText(java.lang.CharSequence);
+    method public void setTextSelection(int, int);
+    method public void setTraversalAfter(android.view.View);
+    method public void setTraversalAfter(android.view.View, int);
+    method public void setTraversalBefore(android.view.View);
+    method public void setTraversalBefore(android.view.View, int);
+    method public void setViewIdResourceName(java.lang.String);
+    method public void setVisibleToUser(boolean);
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+    field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+    field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+    field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+    field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+    field public static final int ACTION_CLICK = 16; // 0x10
+    field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+    field public static final int ACTION_COPY = 16384; // 0x4000
+    field public static final int ACTION_CUT = 65536; // 0x10000
+    field public static final int ACTION_DISMISS = 1048576; // 0x100000
+    field public static final int ACTION_EXPAND = 262144; // 0x40000
+    field public static final int ACTION_FOCUS = 1; // 0x1
+    field public static final int ACTION_LONG_CLICK = 32; // 0x20
+    field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+    field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+    field public static final int ACTION_PASTE = 32768; // 0x8000
+    field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+    field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+    field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+    field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+    field public static final int ACTION_SELECT = 4; // 0x4
+    field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+    field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+    field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+    field public static final int FOCUS_INPUT = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+    field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+    field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+    field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+  }
+
+  public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+    ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, java.lang.CharSequence);
+    method public int getId();
+    method public java.lang.CharSequence getLabel();
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_ACCESSIBILITY_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_SELECTION;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COLLAPSE;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COPY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CUT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DISMISS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_EXPAND;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_FOCUS;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_LONG_CLICK;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PASTE;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_HTML_ELEMENT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_BACKWARD;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_FORWARD;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SELECT;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_SELECTION;
+    field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_TEXT;
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+    method public int getColumnCount();
+    method public int getRowCount();
+    method public boolean isHierarchical();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat obtain(int, int, boolean, int);
+    field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+    field public static final int SELECTION_MODE_NONE = 0; // 0x0
+    field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+    method public int getColumnIndex();
+    method public int getColumnSpan();
+    method public int getRowIndex();
+    method public int getRowSpan();
+    method public boolean isHeading();
+    method public boolean isSelected();
+    method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat obtain(int, int, int, int, boolean, boolean);
+  }
+
+  public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+    method public float getCurrent();
+    method public float getMax();
+    method public float getMin();
+    method public int getType();
+    field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+    field public static final int RANGE_TYPE_INT = 0; // 0x0
+    field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+  }
+
+  public class AccessibilityNodeProviderCompat {
+    ctor public AccessibilityNodeProviderCompat();
+    ctor public AccessibilityNodeProviderCompat(java.lang.Object);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int);
+    method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String, int);
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+    method public java.lang.Object getProvider();
+    method public boolean performAction(int, int, android.os.Bundle);
+  }
+
+  public class AccessibilityRecordCompat {
+    ctor public deprecated AccessibilityRecordCompat(java.lang.Object);
+    method public int getAddedCount();
+    method public java.lang.CharSequence getBeforeText();
+    method public java.lang.CharSequence getClassName();
+    method public java.lang.CharSequence getContentDescription();
+    method public int getCurrentItemIndex();
+    method public int getFromIndex();
+    method public deprecated java.lang.Object getImpl();
+    method public int getItemCount();
+    method public int getMaxScrollX();
+    method public int getMaxScrollY();
+    method public android.os.Parcelable getParcelableData();
+    method public int getRemovedCount();
+    method public int getScrollX();
+    method public int getScrollY();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getSource();
+    method public java.util.List<java.lang.CharSequence> getText();
+    method public int getToIndex();
+    method public int getWindowId();
+    method public boolean isChecked();
+    method public boolean isEnabled();
+    method public boolean isFullScreen();
+    method public boolean isPassword();
+    method public boolean isScrollable();
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain(android.support.v4.view.accessibility.AccessibilityRecordCompat);
+    method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain();
+    method public void recycle();
+    method public void setAddedCount(int);
+    method public void setBeforeText(java.lang.CharSequence);
+    method public void setChecked(boolean);
+    method public void setClassName(java.lang.CharSequence);
+    method public void setContentDescription(java.lang.CharSequence);
+    method public void setCurrentItemIndex(int);
+    method public void setEnabled(boolean);
+    method public void setFromIndex(int);
+    method public void setFullScreen(boolean);
+    method public void setItemCount(int);
+    method public void setMaxScrollX(int);
+    method public void setMaxScrollY(int);
+    method public void setParcelableData(android.os.Parcelable);
+    method public void setPassword(boolean);
+    method public void setRemovedCount(int);
+    method public void setScrollX(int);
+    method public void setScrollY(int);
+    method public void setScrollable(boolean);
+    method public void setSource(android.view.View);
+    method public void setSource(android.view.View, int);
+    method public void setToIndex(int);
+  }
+
+  public class AccessibilityWindowInfoCompat {
+    method public void getBoundsInScreen(android.graphics.Rect);
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getChild(int);
+    method public int getChildCount();
+    method public int getId();
+    method public int getLayer();
+    method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getParent();
+    method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getRoot();
+    method public int getType();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActive();
+    method public boolean isFocused();
+    method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain();
+    method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityWindowInfoCompat);
+    method public void recycle();
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+    field public static final int TYPE_APPLICATION = 1; // 0x1
+    field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SYSTEM = 3; // 0x3
+  }
+
+}
+
+package android.support.v4.view.animation {
+
+  public class FastOutLinearInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public FastOutLinearInInterpolator();
+  }
+
+  public class FastOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public FastOutSlowInInterpolator();
+  }
+
+  public class LinearOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+    ctor public LinearOutSlowInInterpolator();
+  }
+
+   abstract class LookupTableInterpolator implements android.view.animation.Interpolator {
+    ctor public LookupTableInterpolator(float[]);
+    method public float getInterpolation(float);
+  }
+
+  public class PathInterpolatorCompat {
+    method public static android.view.animation.Interpolator create(android.graphics.Path);
+    method public static android.view.animation.Interpolator create(float, float);
+    method public static android.view.animation.Interpolator create(float, float, float, float);
+  }
+
+}
+
+package android.support.v4.widget {
+
+  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+    ctor public AutoScrollHelper(android.view.View);
+    method public abstract boolean canTargetScrollHorizontally(int);
+    method public abstract boolean canTargetScrollVertically(int);
+    method public boolean isEnabled();
+    method public boolean isExclusive();
+    method public boolean onTouch(android.view.View, android.view.MotionEvent);
+    method public abstract void scrollTargetBy(int, int);
+    method public android.support.v4.widget.AutoScrollHelper setActivationDelay(int);
+    method public android.support.v4.widget.AutoScrollHelper setEdgeType(int);
+    method public android.support.v4.widget.AutoScrollHelper setEnabled(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setExclusive(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMinimumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRampDownDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRampUpDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeVelocity(float, float);
+    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+    field public static final float NO_MAX = 3.4028235E38f;
+    field public static final float NO_MIN = 0.0f;
+    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+  }
+
+  public final class CompoundButtonCompat {
+    method public static android.graphics.drawable.Drawable getButtonDrawable(android.widget.CompoundButton);
+    method public static android.content.res.ColorStateList getButtonTintList(android.widget.CompoundButton);
+    method public static android.graphics.PorterDuff.Mode getButtonTintMode(android.widget.CompoundButton);
+    method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList);
+    method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode);
+  }
+
+  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+    ctor public ContentLoadingProgressBar(android.content.Context);
+    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
+    method public void hide();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void show();
+  }
+
+  public abstract class CursorAdapter extends android.widget.BaseAdapter {
+    ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
+    method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursor(android.database.Cursor);
+    method public java.lang.CharSequence convertToString(android.database.Cursor);
+    method public int getCount();
+    method public android.database.Cursor getCursor();
+    method public android.widget.Filter getFilter();
+    method public android.widget.FilterQueryProvider getFilterQueryProvider();
+    method public java.lang.Object getItem(int);
+    method public long getItemId(int);
+    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+    method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+    method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method protected void onContentChanged();
+    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+    field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+    field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
+  }
+
+  public class DrawerLayout extends android.view.ViewGroup {
+    ctor public DrawerLayout(android.content.Context);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void closeDrawer(android.view.View);
+    method public void closeDrawer(int);
+    method public void closeDrawers();
+    method public float getDrawerElevation();
+    method public int getDrawerLockMode(int);
+    method public int getDrawerLockMode(android.view.View);
+    method public java.lang.CharSequence getDrawerTitle(int);
+    method public android.graphics.drawable.Drawable getStatusBarBackgroundDrawable();
+    method public boolean isDrawerOpen(android.view.View);
+    method public boolean isDrawerOpen(int);
+    method public boolean isDrawerVisible(android.view.View);
+    method public boolean isDrawerVisible(int);
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void openDrawer(android.view.View);
+    method public void openDrawer(int);
+    method public void setDrawerElevation(float);
+    method public void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void setDrawerLockMode(int);
+    method public void setDrawerLockMode(int, int);
+    method public void setDrawerLockMode(int, android.view.View);
+    method public void setDrawerShadow(android.graphics.drawable.Drawable, int);
+    method public void setDrawerShadow(int, int);
+    method public void setDrawerTitle(int, java.lang.CharSequence);
+    method public void setScrimColor(int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackground(int);
+    method public void setStatusBarBackgroundColor(int);
+    field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
+    field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+    field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract interface DrawerLayout.DrawerListener {
+    method public abstract void onDrawerClosed(android.view.View);
+    method public abstract void onDrawerOpened(android.view.View);
+    method public abstract void onDrawerSlide(android.view.View, float);
+    method public abstract void onDrawerStateChanged(int);
+  }
+
+  public static class DrawerLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public DrawerLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout.LayoutParams(int, int);
+    ctor public DrawerLayout.LayoutParams(int, int, int);
+    ctor public DrawerLayout.LayoutParams(android.support.v4.widget.DrawerLayout.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    field public int gravity;
+  }
+
+  protected static class DrawerLayout.SavedState extends android.view.View.BaseSavedState {
+    ctor public DrawerLayout.SavedState(android.os.Parcel);
+    ctor public DrawerLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.widget.DrawerLayout.SavedState> CREATOR;
+  }
+
+  public static abstract class DrawerLayout.SimpleDrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public DrawerLayout.SimpleDrawerListener();
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+  }
+
+  public class EdgeEffectCompat {
+    ctor public EdgeEffectCompat(android.content.Context);
+    method public boolean draw(android.graphics.Canvas);
+    method public void finish();
+    method public boolean isFinished();
+    method public boolean onAbsorb(int);
+    method public deprecated boolean onPull(float);
+    method public boolean onPull(float, float);
+    method public boolean onRelease();
+    method public void setSize(int, int);
+  }
+
+  public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public ExploreByTouchHelper(android.view.View);
+    method public boolean dispatchHoverEvent(android.view.MotionEvent);
+    method public int getFocusedVirtualView();
+    method protected abstract int getVirtualViewAt(float, float);
+    method protected abstract void getVisibleVirtualViews(java.util.List<java.lang.Integer>);
+    method public void invalidateRoot();
+    method public void invalidateVirtualView(int);
+    method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
+    method protected abstract void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
+    method public void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public boolean sendEventForVirtualView(int, int);
+    field public static final int HOST_ID = -1; // 0xffffffff
+    field public static final int INVALID_ID = -2147483648; // 0x80000000
+  }
+
+  public class ListPopupWindowCompat {
+    method public static android.view.View.OnTouchListener createDragToOpenListener(java.lang.Object, android.view.View);
+  }
+
+  public class ListViewAutoScrollHelper extends android.support.v4.widget.AutoScrollHelper {
+    ctor public ListViewAutoScrollHelper(android.widget.ListView);
+    method public boolean canTargetScrollHorizontally(int);
+    method public boolean canTargetScrollVertically(int);
+    method public void scrollTargetBy(int, int);
+  }
+
+  public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
+    ctor public NestedScrollView(android.content.Context);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
+    method public boolean arrowScroll(int);
+    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect);
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fling(int);
+    method public boolean fullScroll(int);
+    method public int getMaxScrollAmount();
+    method public boolean isFillViewport();
+    method public boolean isSmoothScrollingEnabled();
+    method public void onAttachedToWindow();
+    method public boolean pageScroll(int);
+    method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
+    method public void setSmoothScrollingEnabled(boolean);
+    method public final void smoothScrollBy(int, int);
+    method public final void smoothScrollTo(int, int);
+  }
+
+  public static abstract interface NestedScrollView.OnScrollChangeListener {
+    method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
+  }
+
+  public class PopupMenuCompat {
+    method public static android.view.View.OnTouchListener getDragToOpenListener(java.lang.Object);
+  }
+
+  public class PopupWindowCompat {
+    method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+    method public static int getWindowLayoutType(android.widget.PopupWindow);
+    method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+    method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+  }
+
+  public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+    ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
+    ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
+    method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public void setDropDownViewResource(int);
+    method public void setViewResource(int);
+  }
+
+  public class ScrollerCompat {
+    method public void abortAnimation();
+    method public boolean computeScrollOffset();
+    method public static android.support.v4.widget.ScrollerCompat create(android.content.Context);
+    method public static android.support.v4.widget.ScrollerCompat create(android.content.Context, android.view.animation.Interpolator);
+    method public void fling(int, int, int, int, int, int, int, int);
+    method public void fling(int, int, int, int, int, int, int, int, int, int);
+    method public float getCurrVelocity();
+    method public int getCurrX();
+    method public int getCurrY();
+    method public int getFinalX();
+    method public int getFinalY();
+    method public boolean isFinished();
+    method public boolean isOverScrolled();
+    method public void notifyHorizontalEdgeReached(int, int, int);
+    method public void notifyVerticalEdgeReached(int, int, int);
+    method public boolean springBack(int, int, int, int, int, int);
+    method public void startScroll(int, int, int, int);
+    method public void startScroll(int, int, int, int, int);
+  }
+
+  public class SearchViewCompat {
+    method public static java.lang.CharSequence getQuery(android.view.View);
+    method public static boolean isIconified(android.view.View);
+    method public static boolean isQueryRefinementEnabled(android.view.View);
+    method public static boolean isSubmitButtonEnabled(android.view.View);
+    method public static android.view.View newSearchView(android.content.Context);
+    method public static void setIconified(android.view.View, boolean);
+    method public static void setImeOptions(android.view.View, int);
+    method public static void setInputType(android.view.View, int);
+    method public static void setMaxWidth(android.view.View, int);
+    method public static void setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat);
+    method public static void setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat);
+    method public static void setQuery(android.view.View, java.lang.CharSequence, boolean);
+    method public static void setQueryHint(android.view.View, java.lang.CharSequence);
+    method public static void setQueryRefinementEnabled(android.view.View, boolean);
+    method public static void setSearchableInfo(android.view.View, android.content.ComponentName);
+    method public static void setSubmitButtonEnabled(android.view.View, boolean);
+  }
+
+  public static abstract class SearchViewCompat.OnCloseListenerCompat {
+    ctor public SearchViewCompat.OnCloseListenerCompat();
+    method public boolean onClose();
+  }
+
+  public static abstract class SearchViewCompat.OnQueryTextListenerCompat {
+    ctor public SearchViewCompat.OnQueryTextListenerCompat();
+    method public boolean onQueryTextChange(java.lang.String);
+    method public boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
+    ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
+    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+    method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+    method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
+    method public int getStringConversionColumn();
+    method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
+    method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
+    method public void setStringConversionColumn(int);
+    method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
+    method public void setViewImage(android.widget.ImageView, java.lang.String);
+    method public void setViewText(android.widget.TextView, java.lang.String);
+  }
+
+  public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
+    method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+  }
+
+  public static abstract interface SimpleCursorAdapter.ViewBinder {
+    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+  }
+
+  public class SlidingPaneLayout extends android.view.ViewGroup {
+    ctor public SlidingPaneLayout(android.content.Context);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public deprecated boolean canSlide();
+    method public boolean closePane();
+    method public int getCoveredFadeColor();
+    method public int getParallaxDistance();
+    method public int getSliderFadeColor();
+    method public boolean isOpen();
+    method public boolean isSlideable();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public boolean openPane();
+    method public void setCoveredFadeColor(int);
+    method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
+    method public void setParallaxDistance(int);
+    method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
+    method public deprecated void setShadowResource(int);
+    method public void setShadowResourceLeft(int);
+    method public void setShadowResourceRight(int);
+    method public void setSliderFadeColor(int);
+    method public deprecated void smoothSlideClosed();
+    method public deprecated void smoothSlideOpen();
+  }
+
+  public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public SlidingPaneLayout.LayoutParams();
+    ctor public SlidingPaneLayout.LayoutParams(int, int);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public float weight;
+  }
+
+  public static abstract interface SlidingPaneLayout.PanelSlideListener {
+    method public abstract void onPanelClosed(android.view.View);
+    method public abstract void onPanelOpened(android.view.View);
+    method public abstract void onPanelSlide(android.view.View, float);
+  }
+
+  public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
+    ctor public SlidingPaneLayout.SimplePanelSlideListener();
+    method public void onPanelClosed(android.view.View);
+    method public void onPanelOpened(android.view.View);
+    method public void onPanelSlide(android.view.View, float);
+  }
+
+  public class Space extends android.view.View {
+    ctor public Space(android.content.Context, android.util.AttributeSet, int);
+    ctor public Space(android.content.Context, android.util.AttributeSet);
+    ctor public Space(android.content.Context);
+  }
+
+  public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+    ctor public SwipeRefreshLayout(android.content.Context);
+    ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
+    method public boolean canChildScrollUp();
+    method public int getProgressCircleDiameter();
+    method public boolean isRefreshing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onMeasure(int, int);
+    method public deprecated void setColorScheme(int...);
+    method public void setColorSchemeColors(int...);
+    method public void setColorSchemeResources(int...);
+    method public void setDistanceToTriggerSync(int);
+    method public void setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener);
+    method public deprecated void setProgressBackgroundColor(int);
+    method public void setProgressBackgroundColorSchemeColor(int);
+    method public void setProgressBackgroundColorSchemeResource(int);
+    method public void setProgressViewEndTarget(boolean, int);
+    method public void setProgressViewOffset(boolean, int, int);
+    method public void setRefreshing(boolean);
+    method public void setSize(int);
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int LARGE = 0; // 0x0
+    field protected int mFrom;
+    field protected int mOriginalOffsetTop;
+  }
+
+  public static abstract interface SwipeRefreshLayout.OnRefreshListener {
+    method public abstract void onRefresh();
+  }
+
+  public class TextViewCompat {
+    method public static int getMaxLines(android.widget.TextView);
+    method public static int getMinLines(android.widget.TextView);
+    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, int, int, int, int);
+  }
+
+  public class ViewDragHelper {
+    method public void abort();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int, int);
+    method public void cancel();
+    method public void captureChildView(android.view.View, int);
+    method public boolean checkTouchSlop(int);
+    method public boolean checkTouchSlop(int, int);
+    method public boolean continueSettling(boolean);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, android.support.v4.widget.ViewDragHelper.Callback);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, float, android.support.v4.widget.ViewDragHelper.Callback);
+    method public android.view.View findTopChildUnder(int, int);
+    method public void flingCapturedView(int, int, int, int);
+    method public int getActivePointerId();
+    method public android.view.View getCapturedView();
+    method public int getEdgeSize();
+    method public float getMinVelocity();
+    method public int getTouchSlop();
+    method public int getViewDragState();
+    method public boolean isCapturedViewUnder(int, int);
+    method public boolean isEdgeTouched(int);
+    method public boolean isEdgeTouched(int, int);
+    method public boolean isPointerDown(int);
+    method public boolean isViewUnder(android.view.View, int, int);
+    method public void processTouchEvent(android.view.MotionEvent);
+    method public void setEdgeTrackingEnabled(int);
+    method public void setMinVelocity(float);
+    method public boolean settleCapturedViewAt(int, int);
+    method public boolean shouldInterceptTouchEvent(android.view.MotionEvent);
+    method public boolean smoothSlideViewTo(android.view.View, int, int);
+    field public static final int DIRECTION_ALL = 3; // 0x3
+    field public static final int DIRECTION_HORIZONTAL = 1; // 0x1
+    field public static final int DIRECTION_VERTICAL = 2; // 0x2
+    field public static final int EDGE_ALL = 15; // 0xf
+    field public static final int EDGE_BOTTOM = 8; // 0x8
+    field public static final int EDGE_LEFT = 1; // 0x1
+    field public static final int EDGE_RIGHT = 2; // 0x2
+    field public static final int EDGE_TOP = 4; // 0x4
+    field public static final int INVALID_POINTER = -1; // 0xffffffff
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class ViewDragHelper.Callback {
+    ctor public ViewDragHelper.Callback();
+    method public int clampViewPositionHorizontal(android.view.View, int, int);
+    method public int clampViewPositionVertical(android.view.View, int, int);
+    method public int getOrderedChildIndex(int);
+    method public int getViewHorizontalDragRange(android.view.View);
+    method public int getViewVerticalDragRange(android.view.View);
+    method public void onEdgeDragStarted(int, int);
+    method public boolean onEdgeLock(int);
+    method public void onEdgeTouched(int, int);
+    method public void onViewCaptured(android.view.View, int);
+    method public void onViewDragStateChanged(int);
+    method public void onViewPositionChanged(android.view.View, int, int, int, int);
+    method public void onViewReleased(android.view.View, float, float);
+    method public abstract boolean tryCaptureView(android.view.View, int);
+  }
+
+}
+
diff --git a/v4/api/current.txt b/v4/api/current.txt
index 3c4290e..9f50a24 100644
--- a/v4/api/current.txt
+++ b/v4/api/current.txt
@@ -26,36 +26,6 @@
 
 }
 
-package android.support.v4.animation {
-
-  public abstract class AnimatorCompatHelper {
-    method public static void clearInterpolator(android.view.View);
-    method public static android.support.v4.animation.ValueAnimatorCompat emptyValueAnimator();
-  }
-
-  public abstract interface AnimatorListenerCompat {
-    method public abstract void onAnimationCancel(android.support.v4.animation.ValueAnimatorCompat);
-    method public abstract void onAnimationEnd(android.support.v4.animation.ValueAnimatorCompat);
-    method public abstract void onAnimationRepeat(android.support.v4.animation.ValueAnimatorCompat);
-    method public abstract void onAnimationStart(android.support.v4.animation.ValueAnimatorCompat);
-  }
-
-  public abstract interface AnimatorUpdateListenerCompat {
-    method public abstract void onAnimationUpdate(android.support.v4.animation.ValueAnimatorCompat);
-  }
-
-  public abstract interface ValueAnimatorCompat {
-    method public abstract void addListener(android.support.v4.animation.AnimatorListenerCompat);
-    method public abstract void addUpdateListener(android.support.v4.animation.AnimatorUpdateListenerCompat);
-    method public abstract void cancel();
-    method public abstract float getAnimatedFraction();
-    method public abstract void setDuration(long);
-    method public abstract void setTarget(android.view.View);
-    method public abstract void start();
-  }
-
-}
-
 package android.support.v4.app {
 
   public deprecated class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
@@ -274,12 +244,14 @@
     method public java.lang.Object getLastCustomNonConfigurationInstance();
     method public android.support.v4.app.FragmentManager getSupportFragmentManager();
     method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+    method public final android.support.v4.media.session.MediaControllerCompat getSupportMediaController();
     method public void onAttachFragment(android.support.v4.app.Fragment);
     method protected void onResumeFragments();
     method public java.lang.Object onRetainCustomNonConfigurationInstance();
     method public final java.lang.Object onRetainNonConfigurationInstance();
     method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
     method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+    method public final void setSupportMediaController(android.support.v4.media.session.MediaControllerCompat);
     method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
     method public void supportFinishAfterTransition();
     method public void supportInvalidateOptionsMenu();
@@ -560,7 +532,7 @@
     field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
   }
 
-  public static class NotificationCompat.Action extends android.support.v4.app.NotificationCompatBase.Action {
+  public static class NotificationCompat.Action {
     ctor public NotificationCompat.Action(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.PendingIntent getActionIntent();
     method public android.os.Bundle getExtras();
@@ -681,7 +653,7 @@
     method public android.support.v4.app.NotificationCompat.CarExtender setUnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation);
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation extends android.support.v4.app.NotificationCompatBase.UnreadConversation {
+  public static class NotificationCompat.CarExtender.UnreadConversation {
     method public long getLatestTimestamp();
     method public java.lang.String[] getMessages();
     method public java.lang.String getParticipant();
@@ -770,23 +742,6 @@
     field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
   }
 
-  public class NotificationCompatBase {
-    ctor public NotificationCompatBase();
-  }
-
-  public static abstract class NotificationCompatBase.Action {
-    ctor public NotificationCompatBase.Action();
-    method public abstract android.app.PendingIntent getActionIntent();
-    method public abstract android.os.Bundle getExtras();
-    method public abstract int getIcon();
-    method public abstract android.support.v4.app.RemoteInputCompatBase.RemoteInput[] getRemoteInputs();
-    method public abstract java.lang.CharSequence getTitle();
-  }
-
-  public static abstract class NotificationCompatBase.UnreadConversation {
-    ctor public NotificationCompatBase.UnreadConversation();
-  }
-
   public final class NotificationCompatExtras {
     field public static final java.lang.String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
     field public static final java.lang.String EXTRA_GROUP_KEY = "android.support.groupKey";
@@ -964,13 +919,13 @@
   public class ContextCompat {
     ctor public ContextCompat();
     method public static int checkSelfPermission(android.content.Context, java.lang.String);
-    method public final java.io.File getCodeCacheDir(android.content.Context);
+    method public static java.io.File getCodeCacheDir(android.content.Context);
     method public static final int getColor(android.content.Context, int);
     method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
     method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
     method public static java.io.File[] getExternalCacheDirs(android.content.Context);
     method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
-    method public final java.io.File getNoBackupFilesDir(android.content.Context);
+    method public static java.io.File getNoBackupFilesDir(android.content.Context);
     method public static java.io.File[] getObbDirs(android.content.Context);
     method public static boolean startActivities(android.content.Context, android.content.Intent[]);
     method public static boolean startActivities(android.content.Context, android.content.Intent[], android.os.Bundle);
@@ -1071,6 +1026,11 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
+  public class ParallelExecutorCompat {
+    ctor public ParallelExecutorCompat();
+    method public static java.util.concurrent.Executor getParallelExecutor();
+  }
+
   public final class PermissionChecker {
     method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
     method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
@@ -1113,6 +1073,8 @@
 
   public class ResourcesCompat {
     ctor public ResourcesCompat();
+    method public static int getColor(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public static android.content.res.ColorStateList getColorStateList(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public static android.graphics.drawable.Drawable getDrawable(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public static android.graphics.drawable.Drawable getDrawableForDensity(android.content.res.Resources, int, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
   }
@@ -1246,6 +1208,77 @@
 
 package android.support.v4.media {
 
+  public final class MediaBrowserCompat {
+    ctor public MediaBrowserCompat(android.content.Context, android.content.ComponentName, android.support.v4.media.MediaBrowserCompat.ConnectionCallback, android.os.Bundle);
+    method public void connect();
+    method public void disconnect();
+    method public android.os.Bundle getExtras();
+    method public void getItem(java.lang.String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+    method public java.lang.String getRoot();
+    method public android.content.ComponentName getServiceComponent();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isConnected();
+    method public void subscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void unsubscribe(java.lang.String);
+  }
+
+  public static class MediaBrowserCompat.ConnectionCallback {
+    ctor public MediaBrowserCompat.ConnectionCallback();
+    method public void onConnected();
+    method public void onConnectionFailed();
+    method public void onConnectionSuspended();
+  }
+
+  public static abstract class MediaBrowserCompat.ItemCallback {
+    ctor public MediaBrowserCompat.ItemCallback();
+    method public void onError(java.lang.String);
+    method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem);
+  }
+
+  public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+    ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public int describeContents();
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public int getFlags();
+    method public java.lang.String getMediaId();
+    method public boolean isBrowsable();
+    method public boolean isPlayable();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem> CREATOR;
+    field public static final int FLAG_BROWSABLE = 1; // 0x1
+    field public static final int FLAG_PLAYABLE = 2; // 0x2
+  }
+
+  public static abstract class MediaBrowserCompat.SubscriptionCallback {
+    ctor public MediaBrowserCompat.SubscriptionCallback();
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+    method public void onError(java.lang.String);
+  }
+
+  public abstract class MediaBrowserServiceCompat extends android.app.Service {
+    ctor public MediaBrowserServiceCompat();
+    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public void notifyChildrenChanged(java.lang.String);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
+    method public abstract void onLoadChildren(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>);
+    method public void onLoadItem(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+    method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+  }
+
+  public static final class MediaBrowserServiceCompat.BrowserRoot {
+    ctor public MediaBrowserServiceCompat.BrowserRoot(java.lang.String, android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getRootId();
+  }
+
+  public static class MediaBrowserServiceCompat.Result {
+    method public void detach();
+    method public void sendResult(T);
+  }
+
   public final class MediaDescriptionCompat implements android.os.Parcelable {
     method public int describeContents();
     method public static android.support.v4.media.MediaDescriptionCompat fromMediaDescription(java.lang.Object);
@@ -1449,6 +1482,12 @@
 
 package android.support.v4.media.session {
 
+  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+    ctor public MediaButtonReceiver();
+    method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
+    method public void onReceive(android.content.Context, android.content.Intent);
+  }
+
   public final class MediaControllerCompat {
     ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
     ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
@@ -1516,6 +1555,7 @@
   }
 
   public class MediaSessionCompat {
+    ctor public MediaSessionCompat(android.content.Context, java.lang.String);
     ctor public MediaSessionCompat(android.content.Context, java.lang.String, android.content.ComponentName, android.app.PendingIntent);
     method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
     method public android.support.v4.media.session.MediaControllerCompat getController();
@@ -2349,6 +2389,13 @@
     method public abstract int computeVerticalScrollRange();
   }
 
+  public abstract interface TintableBackgroundView {
+    method public abstract android.content.res.ColorStateList getSupportBackgroundTintList();
+    method public abstract android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+    method public abstract void setSupportBackgroundTintList(android.content.res.ColorStateList);
+    method public abstract void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
+  }
+
   public class VelocityTrackerCompat {
     ctor public VelocityTrackerCompat();
     method public static float getXVelocity(android.view.VelocityTracker, int);
@@ -2396,6 +2443,7 @@
     method public static float getRotationY(android.view.View);
     method public static float getScaleX(android.view.View);
     method public static float getScaleY(android.view.View);
+    method public static int getScrollIndicators(android.view.View);
     method public static java.lang.String getTransitionName(android.view.View);
     method public static float getTranslationX(android.view.View);
     method public static float getTranslationY(android.view.View);
@@ -2406,6 +2454,7 @@
     method public static float getZ(android.view.View);
     method public static boolean hasAccessibilityDelegate(android.view.View);
     method public static boolean hasNestedScrollingParent(android.view.View);
+    method public static boolean hasOnClickListeners(android.view.View);
     method public static boolean hasOverlappingRendering(android.view.View);
     method public static boolean hasTransientState(android.view.View);
     method public static boolean isAttachedToWindow(android.view.View);
@@ -2455,6 +2504,8 @@
     method public static void setSaveFromParentEnabled(android.view.View, boolean);
     method public static void setScaleX(android.view.View, float);
     method public static void setScaleY(android.view.View, float);
+    method public static void setScrollIndicators(android.view.View, int);
+    method public static void setScrollIndicators(android.view.View, int, int);
     method public static void setTransitionName(android.view.View, java.lang.String);
     method public static void setTranslationX(android.view.View, float);
     method public static void setTranslationY(android.view.View, float);
@@ -2487,6 +2538,12 @@
     field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
     field public static final int SCROLL_AXIS_NONE = 0; // 0x0
     field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+    field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+    field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+    field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+    field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
   }
 
   public class ViewConfigurationCompat {
@@ -3138,6 +3195,7 @@
     method public void setStatusBarBackgroundColor(int);
     field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
     field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+    field public static final int LOCK_MODE_UNDEFINED = 3; // 0x3
     field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
     field public static final int STATE_DRAGGING = 1; // 0x1
     field public static final int STATE_IDLE = 0; // 0x0
@@ -3215,7 +3273,7 @@
     method public void scrollTargetBy(int, int);
   }
 
-  public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+  public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
     ctor public NestedScrollView(android.content.Context);
     ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
     ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
@@ -3230,11 +3288,16 @@
     method public void onAttachedToWindow();
     method public boolean pageScroll(int);
     method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
     method public void setSmoothScrollingEnabled(boolean);
     method public final void smoothScrollBy(int, int);
     method public final void smoothScrollTo(int, int);
   }
 
+  public static abstract interface NestedScrollView.OnScrollChangeListener {
+    method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
+  }
+
   public class PopupMenuCompat {
     method public static android.view.View.OnTouchListener getDragToOpenListener(java.lang.Object);
   }
@@ -3272,6 +3335,7 @@
     method public boolean isOverScrolled();
     method public void notifyHorizontalEdgeReached(int, int, int);
     method public void notifyVerticalEdgeReached(int, int, int);
+    method public boolean springBack(int, int, int, int, int, int);
     method public void startScroll(int, int, int, int);
     method public void startScroll(int, int, int, int, int);
   }
@@ -3417,9 +3481,19 @@
   }
 
   public class TextViewCompat {
+    method public static int getMaxLines(android.widget.TextView);
+    method public static int getMinLines(android.widget.TextView);
     method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, int, int, int, int);
+    method public static void setTextAppearance(android.widget.TextView, int);
+  }
+
+  public abstract interface TintableCompoundButton {
+    method public abstract android.content.res.ColorStateList getSupportButtonTintList();
+    method public abstract android.graphics.PorterDuff.Mode getSupportButtonTintMode();
+    method public abstract void setSupportButtonTintList(android.content.res.ColorStateList);
+    method public abstract void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class ViewDragHelper {
diff --git a/v4/api21/android/content/pm/ParceledListSlice.java b/v4/api21/android/content/pm/ParceledListSlice.java
new file mode 100644
index 0000000..b5183c0
--- /dev/null
+++ b/v4/api21/android/content/pm/ParceledListSlice.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * A dummy implementation for overriding a hidden framework class, ParceledListSlice.
+ * When there are duplicated signatures between app and framework code, the framework code will be
+ * run.
+ * @hide
+ */
+public class ParceledListSlice<T extends Parcelable> implements Parcelable {
+    public ParceledListSlice(List<T> list) {
+    }
+
+    @SuppressWarnings("unchecked")
+    private ParceledListSlice(Parcel p, ClassLoader loader) {
+    }
+
+    private static void verifySameType(final Class<?> expected, final Class<?> actual) {
+    }
+
+    public List<T> getList() {
+        return null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+
+    @SuppressWarnings("unchecked")
+    public static final Parcelable.ClassLoaderCreator<ParceledListSlice> CREATOR =
+            new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
+        public ParceledListSlice createFromParcel(Parcel in) {
+            return null;
+        }
+
+        @Override
+        public ParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
+            return null;
+        }
+
+        public ParceledListSlice[] newArray(int size) {
+            return null;
+        }
+    };
+}
diff --git a/v4/api21/android/service/media/IMediaBrowserService.java b/v4/api21/android/service/media/IMediaBrowserService.java
new file mode 100644
index 0000000..086dc9cc
--- /dev/null
+++ b/v4/api21/android/service/media/IMediaBrowserService.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package android.service.media;
+
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+
+/**
+ * A dummy implementation for overriding a hidden framework class, IMediaBrowserService.
+ * When there are duplicated signatures between app and framework code, the framework code will be
+ * run.
+ * TODO: Consider using aidl instead of this.
+ * @hide
+ */
+public interface IMediaBrowserService extends IInterface {
+
+    public static abstract class Stub extends Binder
+            implements IMediaBrowserService {
+        public Stub() {
+        }
+
+        public static IMediaBrowserService asInterface(IBinder obj) {
+            return null;
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return null;
+        }
+
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws android.os.RemoteException {
+            return false;
+        }
+    }
+
+    public void connect(String pkg, Bundle rootHints, IMediaBrowserServiceCallbacks callbacks)
+            throws android.os.RemoteException;
+    public void disconnect(IMediaBrowserServiceCallbacks callbacks) throws RemoteException;
+    public void addSubscription(String uri, IMediaBrowserServiceCallbacks callbacks)
+            throws RemoteException;
+    public void removeSubscription(String uri, IMediaBrowserServiceCallbacks callbacks)
+            throws RemoteException;
+    public void getMediaItem(String uri, ResultReceiver cb) throws android.os.RemoteException;
+}
diff --git a/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java b/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java
new file mode 100644
index 0000000..fe988fe
--- /dev/null
+++ b/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+package android.service.media;
+
+import android.content.pm.ParceledListSlice;
+import android.media.session.MediaSession;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * A dummy implementation for overriding a hidden framework class, IMediaBrowserServiceCallbacks.
+ * When there are duplicated signatures between app and framework code, the framework code will be
+ * run.
+ * TODO: Consider using aidl instead of this.
+ * @hide
+ */
+public interface IMediaBrowserServiceCallbacks extends IInterface {
+    public static abstract class Stub extends Binder implements IMediaBrowserServiceCallbacks
+    {
+        public Stub() {
+        }
+
+        public static IMediaBrowserServiceCallbacks asInterface(IBinder obj) {
+            return null;
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return null;
+        }
+
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            return false;
+        }
+
+        private static class Proxy implements IMediaBrowserServiceCallbacks
+        {
+            Proxy(IBinder remote) {
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return null;
+            }
+
+            public String getInterfaceDescriptor() {
+                return null;
+            }
+
+            @Override
+            public void onConnect(String root, MediaSession.Token session, Bundle extras)
+                    throws RemoteException {
+            }
+
+            @Override
+            public void onConnectFailed() throws RemoteException {
+            }
+
+            @Override
+            public void onLoadChildren(String mediaId, ParceledListSlice list)
+                    throws RemoteException {
+            }
+        }
+    }
+
+    public void onConnect(String root, MediaSession.Token session, Bundle extras)
+            throws RemoteException;
+    public void onConnectFailed() throws RemoteException;
+    public void onLoadChildren(String mediaId, ParceledListSlice list) throws RemoteException;
+}
+
diff --git a/v4/api21/android/support/v4/app/ActivityCompat21.java b/v4/api21/android/support/v4/app/ActivityCompat21.java
index f690fff..2e6de1e 100644
--- a/v4/api21/android/support/v4/app/ActivityCompat21.java
+++ b/v4/api21/android/support/v4/app/ActivityCompat21.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.RectF;
+import android.media.session.MediaController;
 import android.os.Parcelable;
 import android.view.View;
 
@@ -31,6 +32,10 @@
 
 class ActivityCompat21 {
 
+    public static void setMediaController(Activity activity, Object mediaControllerObj) {
+        activity.setMediaController((MediaController) mediaControllerObj);
+    }
+
     public static void finishAfterTransition(Activity activity) {
         activity.finishAfterTransition();
     }
diff --git a/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java b/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
index 93990b4..2f3b45a 100644
--- a/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
+++ b/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
@@ -37,46 +37,28 @@
     }
 
     public static void setTint(Drawable drawable, int tint) {
-        if (drawable instanceof DrawableWrapperLollipop) {
-            // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
-            // functionality instead
-            DrawableCompatBase.setTint(drawable, tint);
-        } else {
-            // Else, we'll use the framework API
-            drawable.setTint(tint);
-        }
+        drawable.setTint(tint);
     }
 
     public static void setTintList(Drawable drawable, ColorStateList tint) {
-        if (drawable instanceof DrawableWrapperLollipop) {
-            // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
-            // functionality instead
-            DrawableCompatBase.setTintList(drawable, tint);
-        } else {
-            // Else, we'll use the framework API
-            drawable.setTintList(tint);
-        }
+        drawable.setTintList(tint);
     }
 
     public static void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
-        if (drawable instanceof DrawableWrapperLollipop) {
-            // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
-            // functionality instead
-            DrawableCompatBase.setTintMode(drawable, tintMode);
-        } else {
-            // Else, we'll use the framework API
-            drawable.setTintMode(tintMode);
-        }
+        drawable.setTintMode(tintMode);
     }
 
-    public static Drawable wrapForTinting(Drawable drawable) {
-        if (drawable instanceof GradientDrawable || drawable instanceof DrawableContainer) {
-            // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
-            // functionality instead. We also do the same for DrawableContainers since they may
-            // contain GradientDrawable instances.
-            return new DrawableWrapperLollipop(drawable);
+    public static Drawable wrapForTinting(final Drawable drawable) {
+        if (!(drawable instanceof DrawableWrapperLollipop)) {
+            return new DrawableWrapperLollipop(drawable, shouldForceCompatTinting(drawable));
         }
         return drawable;
     }
 
+    private static boolean shouldForceCompatTinting(Drawable drawable) {
+        // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
+        // functionality instead. We also do the same for DrawableContainers since they may
+        // contain GradientDrawable instances.
+        return drawable instanceof GradientDrawable || drawable instanceof DrawableContainer;
+    }
 }
diff --git a/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java b/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
index 1f15040..9533afd 100644
--- a/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
+++ b/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
@@ -16,15 +16,24 @@
 
 package android.support.v4.graphics.drawable;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Outline;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 
 class DrawableWrapperLollipop extends DrawableWrapperKitKat {
 
+    private final boolean mUseCompatTinting;
+
     DrawableWrapperLollipop(Drawable drawable) {
+        this(drawable, false);
+    }
+
+    DrawableWrapperLollipop(Drawable drawable, boolean useCompatTinting) {
         super(drawable);
+        mUseCompatTinting = useCompatTinting;
     }
 
     @Override
@@ -56,4 +65,47 @@
     public Rect getDirtyBounds() {
         return mDrawable.getDirtyBounds();
     }
+
+    @Override
+    public void setTintList(ColorStateList tint) {
+        if (mUseCompatTinting) {
+            setCompatTintList(tint);
+        } else {
+            mDrawable.setTintList(tint);
+        }
+    }
+
+    @Override
+    public void setTint(int tintColor) {
+        if (mUseCompatTinting) {
+            setCompatTint(tintColor);
+        } else {
+            mDrawable.setTint(tintColor);
+        }
+    }
+
+    @Override
+    public void setTintMode(PorterDuff.Mode tintMode) {
+        if (mUseCompatTinting) {
+            setCompatTintMode(tintMode);
+        } else {
+            mDrawable.setTintMode(tintMode);
+        }
+    }
+
+    @Override
+    public boolean setState(int[] stateSet) {
+        if (super.setState(stateSet)) {
+            // Manually invalidate because the framework doesn't currently force an invalidation
+            // on a state change
+            invalidateSelf();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean isCompatTintEnabled() {
+        return mUseCompatTinting;
+    }
 }
diff --git a/v4/api21/android/support/v4/media/MediaBrowserCompatApi21.java b/v4/api21/android/support/v4/media/MediaBrowserCompatApi21.java
new file mode 100644
index 0000000..c6ccb14
--- /dev/null
+++ b/v4/api21/android/support/v4/media/MediaBrowserCompatApi21.java
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.media.browse.MediaBrowser;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MediaBrowserCompatApi21 {
+    static final String NULL_MEDIA_ITEM_ID =
+            "android.support.v4.media.MediaBrowserCompat.NULL_MEDIA_ITEM";
+
+    public static Object createConnectionCallback(ConnectionCallback callback) {
+        return new ConnectionCallbackProxy<>(callback);
+    }
+
+    public static Object createBrowser(Context context, ComponentName serviceComponent,
+            Object callback, Bundle rootHints) {
+        return new MediaBrowser(context, serviceComponent,
+                (MediaBrowser.ConnectionCallback) callback, rootHints);
+    }
+
+    public static void connect(Object browserObj) {
+        ((MediaBrowser)browserObj).connect();
+    }
+
+    public static void disconnect(Object browserObj) {
+        ((MediaBrowser)browserObj).disconnect();
+
+    }
+
+    public static boolean isConnected(Object browserObj) {
+        return ((MediaBrowser)browserObj).isConnected();
+    }
+
+    public static ComponentName getServiceComponent(Object browserObj) {
+        return ((MediaBrowser)browserObj).getServiceComponent();
+    }
+
+    public static String getRoot(Object browserObj) {
+        return ((MediaBrowser)browserObj).getRoot();
+    }
+
+    public static Bundle getExtras(Object browserObj) {
+        return ((MediaBrowser)browserObj).getExtras();
+    }
+
+    public static Object getSessionToken(Object browserObj) {
+        return ((MediaBrowser)browserObj).getSessionToken();
+    }
+
+    public static Object createSubscriptionCallback(SubscriptionCallback callback) {
+        return new SubscriptionCallbackProxy<>(callback);
+    }
+
+    public static void subscribe(
+            Object browserObj, String parentId, Object subscriptionCallbackObj) {
+        ((MediaBrowser)browserObj).subscribe(parentId,
+                (MediaBrowser.SubscriptionCallback) subscriptionCallbackObj);
+    }
+
+    public static void unsubscribe(Object browserObj, String parentId) {
+        ((MediaBrowser)browserObj).unsubscribe(parentId);
+    }
+
+    interface ConnectionCallback {
+        void onConnected();
+        void onConnectionSuspended();
+        void onConnectionFailed();
+    }
+
+    static class ConnectionCallbackProxy<T extends ConnectionCallback>
+            extends MediaBrowser.ConnectionCallback {
+        protected final T mConnectionCallback;
+
+        public ConnectionCallbackProxy(T connectionCallback) {
+            mConnectionCallback = connectionCallback;
+        }
+
+        @Override
+        public void onConnected() {
+            mConnectionCallback.onConnected();
+        }
+
+        @Override
+        public void onConnectionSuspended() {
+            mConnectionCallback.onConnectionSuspended();
+        }
+
+        @Override
+        public void onConnectionFailed() {
+            mConnectionCallback.onConnectionFailed();
+        }
+    }
+
+    interface SubscriptionCallback {
+        void onChildrenLoaded(@NonNull String parentId, List<Parcel> children);
+        void onError(@NonNull String parentId);
+    }
+
+    static class SubscriptionCallbackProxy<T extends SubscriptionCallback>
+            extends MediaBrowser.SubscriptionCallback {
+        protected final T mSubscriptionCallback;
+
+        public SubscriptionCallbackProxy(T callback) {
+            mSubscriptionCallback = callback;
+        }
+
+        @Override
+        public void onChildrenLoaded(@NonNull String parentId,
+                List<MediaBrowser.MediaItem> children) {
+            List<Parcel> parcelList = null;
+            if (children != null && children.size() == 1
+                    && children.get(0).getMediaId().equals(NULL_MEDIA_ITEM_ID)) {
+                children = null;
+            }
+            if (children != null) {
+                parcelList = new ArrayList<>();
+                for (MediaBrowser.MediaItem item : children) {
+                    Parcel parcel = Parcel.obtain();
+                    item.writeToParcel(parcel, 0);
+                    parcelList.add(parcel);
+                }
+            }
+            mSubscriptionCallback.onChildrenLoaded(parentId, parcelList);
+        }
+
+        @Override
+        public void onError(@NonNull String parentId) {
+            mSubscriptionCallback.onError(parentId);
+        }
+    }
+}
diff --git a/v4/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java b/v4/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java
new file mode 100644
index 0000000..a1506d3
--- /dev/null
+++ b/v4/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.media.MediaDescription;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaSession;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.service.media.IMediaBrowserService;
+import android.service.media.IMediaBrowserServiceCallbacks;
+import android.service.media.MediaBrowserService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MediaBrowserServiceCompatApi21 {
+
+    public static Object createService() {
+        return new MediaBrowserServiceAdaptorApi21();
+    }
+
+    public static void onCreate(Object serviceObj, ServiceImplApi21 serviceImpl) {
+        ((MediaBrowserServiceAdaptorApi21) serviceObj).onCreate(serviceImpl);
+    }
+
+    public static IBinder onBind(Object serviceObj, Intent intent) {
+        return ((MediaBrowserServiceAdaptorApi21) serviceObj).onBind(intent);
+    }
+
+    public interface ServiceImplApi21 {
+        void connect(final String pkg, final Bundle rootHints, final ServiceCallbacks callbacks);
+        void disconnect(final ServiceCallbacks callbacks);
+        void addSubscription(final String id, final ServiceCallbacks callbacks);
+        void removeSubscription(final String id, final ServiceCallbacks callbacks);
+    }
+
+    public interface ServiceCallbacks {
+        IBinder asBinder();
+        void onConnect(String root, Object session, Bundle extras) throws RemoteException;
+        void onConnectFailed() throws RemoteException;
+        void onLoadChildren(String mediaId, List<Parcel> list) throws RemoteException;
+    }
+
+    public static class ServiceCallbacksApi21 implements ServiceCallbacks {
+        private static final ParceledListSlice sNullParceledListSlice;
+        static {
+            MediaDescription nullDescription = new MediaDescription.Builder().setMediaId(
+                    MediaBrowserCompatApi21.NULL_MEDIA_ITEM_ID).build();
+            MediaBrowser.MediaItem nullMediaItem = new MediaBrowser.MediaItem(nullDescription, 0);
+            List<MediaBrowser.MediaItem> nullMediaItemList = new ArrayList<>();
+            nullMediaItemList.add(nullMediaItem);
+            sNullParceledListSlice = new ParceledListSlice(nullMediaItemList);
+        }
+
+        private final IMediaBrowserServiceCallbacks mCallbacks;
+
+        ServiceCallbacksApi21(IMediaBrowserServiceCallbacks callbacks) {
+            mCallbacks = callbacks;
+        }
+
+        public IBinder asBinder() {
+            return mCallbacks.asBinder();
+        }
+
+        public void onConnect(String root, Object session, Bundle extras) throws RemoteException {
+            mCallbacks.onConnect(root, (MediaSession.Token) session, extras);
+        }
+
+        public void onConnectFailed() throws RemoteException {
+            mCallbacks.onConnectFailed();
+        }
+
+        public void onLoadChildren(String mediaId, List<Parcel> list) throws RemoteException {
+            List<MediaBrowser.MediaItem> itemList = null;
+            if (list != null) {
+                itemList = new ArrayList<>();
+                for (Parcel parcel : list) {
+                    parcel.setDataPosition(0);
+                    itemList.add(MediaBrowser.MediaItem.CREATOR.createFromParcel(parcel));
+                    parcel.recycle();
+                }
+            }
+            ParceledListSlice<MediaBrowser.MediaItem> pls;
+            if (Build.VERSION.SDK_INT > 23) {
+                pls = itemList == null ? null : new ParceledListSlice(itemList);
+            } else {
+                pls = itemList == null ? sNullParceledListSlice : new ParceledListSlice(itemList);
+            }
+            mCallbacks.onLoadChildren(mediaId, pls);
+        }
+    }
+
+    static class MediaBrowserServiceAdaptorApi21 {
+        ServiceBinderProxyApi21 mBinder;
+
+        public void onCreate(ServiceImplApi21 serviceImpl) {
+            mBinder = new ServiceBinderProxyApi21(serviceImpl);
+        }
+
+        public IBinder onBind(Intent intent) {
+            if (MediaBrowserService.SERVICE_INTERFACE.equals(intent.getAction())) {
+                return mBinder;
+            }
+            return null;
+        }
+
+        static class ServiceBinderProxyApi21 extends IMediaBrowserService.Stub {
+            final ServiceImplApi21 mServiceImpl;
+
+            ServiceBinderProxyApi21(ServiceImplApi21 serviceImpl) {
+                mServiceImpl = serviceImpl;
+            }
+
+            @Override
+            public void connect(final String pkg, final Bundle rootHints,
+                    final IMediaBrowserServiceCallbacks callbacks) {
+                mServiceImpl.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks));
+            }
+
+            @Override
+            public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
+                mServiceImpl.disconnect(new ServiceCallbacksApi21(callbacks));
+            }
+
+
+            @Override
+            public void addSubscription(final String id,
+                    final IMediaBrowserServiceCallbacks callbacks) {
+                mServiceImpl.addSubscription(id, new ServiceCallbacksApi21(callbacks));
+            }
+
+            @Override
+            public void removeSubscription(final String id,
+                    final IMediaBrowserServiceCallbacks callbacks) {
+                mServiceImpl.removeSubscription(id, new ServiceCallbacksApi21(callbacks));
+            }
+
+            @Override
+            public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
+                // No operation since this method is added in API 23.
+            }
+        }
+    }
+}
diff --git a/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java b/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
index 991515a..234a77a 100644
--- a/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
+++ b/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
@@ -21,7 +21,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 
-public class MediaDescriptionCompatApi21 {
+class MediaDescriptionCompatApi21 {
 
     public static String getMediaId(Object descriptionObj) {
         return ((MediaDescription) descriptionObj).getMediaId();
@@ -59,7 +59,7 @@
         return MediaDescription.CREATOR.createFromParcel(in);
     }
 
-    public static class Builder {
+    static class Builder {
         public static Object newInstance() {
             return new MediaDescription.Builder();
         }
diff --git a/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java b/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java
index eddcf76..fd51f78 100644
--- a/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java
+++ b/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.media.MediaMetadata;
 import android.media.Rating;
+import android.os.Parcel;
 
 import java.util.Set;
 
@@ -43,6 +44,14 @@
         return ((MediaMetadata) metadataObj).getText(key);
     }
 
+    public static void writeToParcel(Object metadataObj, Parcel dest, int flags) {
+        ((MediaMetadata) metadataObj).writeToParcel(dest, flags);
+    }
+
+    public static Object createFromParcel(Parcel in) {
+        return MediaMetadata.CREATOR.createFromParcel(in);
+    }
+
     public static class Builder {
         public static Object newInstance() {
             return new MediaMetadata.Builder();
diff --git a/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java b/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
index 8094391..b3e7fd1 100644
--- a/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
+++ b/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
@@ -132,7 +132,7 @@
         ((MediaSession) sessionObj).setExtras(extras);
     }
 
-    public static interface Callback {
+    static interface Callback {
         public void onCommand(String command, Bundle extras, ResultReceiver cb);
         public boolean onMediaButtonEvent(Intent mediaButtonIntent);
         public void onPlay();
diff --git a/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java b/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java
index bfd2bea..50f2657 100644
--- a/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java
+++ b/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java
@@ -24,8 +24,8 @@
 class DrawableCompatApi22 {
 
     public static Drawable wrapForTinting(Drawable drawable) {
-        // We don't need to wrap anything in Lollipop-MR1
-        return drawable;
+        // We need to wrap to force an invalidation on any state change
+        return new DrawableWrapperLollipop(drawable);
     }
 
 }
diff --git a/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java b/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
index 64a1206..72e07bf 100644
--- a/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
+++ b/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
@@ -22,7 +22,7 @@
 /**
  * AppOpsManager implementations for API 23.
  */
-public class AppOpsManagerCompat23 {
+class AppOpsManagerCompat23 {
     public static String permissionToOp(String permission) {
         return AppOpsManager.permissionToOp(permission);
     }
diff --git a/v4/api23/android/support/v4/content/ResourcesCompatApi23.java b/v4/api23/android/support/v4/content/ResourcesCompatApi23.java
new file mode 100644
index 0000000..c44f9ce
--- /dev/null
+++ b/v4/api23/android/support/v4/content/ResourcesCompatApi23.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.content.res;
+
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+
+class ResourcesCompatApi23 {
+    public static int getColor(Resources res, int id, Theme theme) throws NotFoundException {
+        return res.getColor(id, theme);
+    }
+
+    public static ColorStateList getColorStateList(Resources res, int id, Theme theme)
+            throws NotFoundException {
+        return res.getColorStateList(id, theme);
+    }
+}
diff --git a/v4/api23/android/support/v4/media/MediaBrowserCompatApi23.java b/v4/api23/android/support/v4/media/MediaBrowserCompatApi23.java
new file mode 100644
index 0000000..1e9df1a
--- /dev/null
+++ b/v4/api23/android/support/v4/media/MediaBrowserCompatApi23.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.media.browse.MediaBrowser;
+import android.os.Parcel;
+import android.support.annotation.NonNull;
+
+class MediaBrowserCompatApi23 {
+
+    public static Object createItemCallback(ItemCallback callback) {
+        return new ItemCallbackProxy<>(callback);
+    }
+
+    public static void getItem(Object browserObj, String mediaId, Object itemCallbackObj) {
+        ((MediaBrowser) browserObj).getItem(mediaId, ((MediaBrowser.ItemCallback) itemCallbackObj));
+    }
+
+    interface ItemCallback {
+        void onItemLoaded(Parcel itemParcel);
+        void onError(@NonNull String itemId);
+    }
+
+    static class ItemCallbackProxy<T extends ItemCallback> extends MediaBrowser.ItemCallback {
+        protected final T mItemCallback;
+
+        public ItemCallbackProxy(T callback) {
+            mItemCallback = callback;
+        }
+
+        @Override
+        public void onItemLoaded(MediaBrowser.MediaItem item) {
+            Parcel parcel = Parcel.obtain();
+            item.writeToParcel(parcel, 0);
+            mItemCallback.onItemLoaded(parcel);
+        }
+
+        @Override
+        public void onError(@NonNull String itemId) {
+            mItemCallback.onError(itemId);
+        }
+    }
+}
diff --git a/v4/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java b/v4/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java
new file mode 100644
index 0000000..fcaea40
--- /dev/null
+++ b/v4/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.media.browse.MediaBrowser;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+import android.service.media.MediaBrowserService;
+import android.util.Log;
+
+class MediaBrowserServiceCompatApi23 extends MediaBrowserServiceCompatApi21 {
+    private static final String TAG = "MediaBrowserServiceCompatApi21";
+
+    public static Object createService() {
+        return new MediaBrowserServiceAdaptorApi23();
+    }
+
+    public static void onCreate(Object serviceObj, ServiceImplApi23 serviceImpl) {
+        ((MediaBrowserServiceAdaptorApi23) serviceObj).onCreate(serviceImpl);
+    }
+
+    public interface ServiceImplApi23 extends ServiceImplApi21 {
+        void getMediaItem(final String mediaId, final ItemCallback cb);
+    }
+
+    public interface ItemCallback {
+        void onItemLoaded(int resultCode, Bundle resultData, Parcel itemParcel);
+    }
+
+    static class MediaBrowserServiceAdaptorApi23 extends MediaBrowserServiceAdaptorApi21 {
+
+        public void onCreate(ServiceImplApi23 serviceImpl) {
+            mBinder = new ServiceBinderProxyApi23(serviceImpl);
+        }
+
+        private static class ServiceBinderProxyApi23 extends ServiceBinderProxyApi21 {
+            ServiceImplApi23 mServiceImpl;
+
+            ServiceBinderProxyApi23(ServiceImplApi23 serviceImpl) {
+                super(serviceImpl);
+                mServiceImpl = serviceImpl;
+            }
+
+            @Override
+            public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
+                final String KEY_MEDIA_ITEM;
+                try {
+                    KEY_MEDIA_ITEM = (String) MediaBrowserService.class.getDeclaredField(
+                            "KEY_MEDIA_ITEM").get(null);
+                } catch (IllegalAccessException | NoSuchFieldException e) {
+                    Log.i(TAG, "Failed to get KEY_MEDIA_ITEM via reflection", e);
+                    return;
+                }
+
+                mServiceImpl.getMediaItem(mediaId, new ItemCallback() {
+                    @Override
+                    public void onItemLoaded(int resultCode, Bundle resultData, Parcel itemParcel) {
+                        if (itemParcel != null) {
+                            itemParcel.setDataPosition(0);
+                            MediaBrowser.MediaItem item =
+                                    MediaBrowser.MediaItem.CREATOR.createFromParcel(itemParcel);
+                            resultData.putParcelable(KEY_MEDIA_ITEM, item);
+                            itemParcel.recycle();
+                        }
+                        receiver.send(resultCode, resultData);
+                    }
+                });
+            }
+        }
+    }
+}
diff --git a/v4/api23/android/support/v4/text/ICUCompatApi23.java b/v4/api23/android/support/v4/text/ICUCompatApi23.java
index f013522..1a3c54f 100644
--- a/v4/api23/android/support/v4/text/ICUCompatApi23.java
+++ b/v4/api23/android/support/v4/text/ICUCompatApi23.java
@@ -22,7 +22,7 @@
 import java.lang.reflect.Method;
 import java.util.Locale;
 
-public class ICUCompatApi23 {
+class ICUCompatApi23 {
 
     private static final String TAG = "ICUCompatIcs";
 
diff --git a/v4/api23/android/support/v4/view/ViewCompatMarshmallow.java b/v4/api23/android/support/v4/view/ViewCompatMarshmallow.java
new file mode 100644
index 0000000..16d3ae8
--- /dev/null
+++ b/v4/api23/android/support/v4/view/ViewCompatMarshmallow.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.view;
+
+import android.view.View;
+
+class ViewCompatMarshmallow {
+    public static void setScrollIndicators(View view, int indicators) {
+        view.setScrollIndicators(indicators);
+    }
+
+    public static void setScrollIndicators(View view, int indicators, int mask) {
+        view.setScrollIndicators(indicators, mask);
+    }
+
+    public static int getScrollIndicators(View view) {
+        return view.getScrollIndicators();
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v4/api23/android/support/v4/widget/TextViewCompatApi23.java
similarity index 60%
copy from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
copy to v4/api23/android/support/v4/widget/TextViewCompatApi23.java
index 8eea38d..8370bfc 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v4/api23/android/support/v4/widget/TextViewCompatApi23.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,17 +14,14 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v4.widget;
 
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
+import android.support.annotation.IdRes;
+import android.support.annotation.NonNull;
+import android.widget.TextView;
 
-/**
- * @hide
- */
-public class TintInfo {
-    public ColorStateList mTintList;
-    public PorterDuff.Mode mTintMode;
-    public boolean mHasTintMode;
-    public boolean mHasTintList;
+class TextViewCompatApi23 {
+    public static void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+        textView.setTextAppearance(resId);
+    }
 }
diff --git a/v4/build.gradle b/v4/build.gradle
index a056973..ba65cab 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -64,6 +64,10 @@
     // depend on the generation of this jar. This is done below
     // when manipulating the libraryVariants.
     compile files(internalJar.archivePath)
+
+    androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
+    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
+    testCompile 'junit:junit:4.12'
 }
 
 android {
@@ -73,6 +77,8 @@
         minSdkVersion 4
         // TODO: get target from branch
         //targetSdkVersion 19
+
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     sourceSets {
@@ -82,6 +88,8 @@
 
         androidTest.setRoot('tests')
         androidTest.java.srcDir 'tests/java'
+        androidTest.res.srcDir 'tests/res'
+        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
     }
 
     lintOptions {
@@ -93,6 +101,10 @@
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
+
+    testOptions {
+        unitTests.returnDefaultValues = true
+    }
 }
 
 android.libraryVariants.all { variant ->
@@ -124,6 +136,8 @@
     def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
         classifier = 'sources'
         from android.sourceSets.main.java.srcDirs
+        exclude('android/content/pm/**')
+        exclude('android/service/media/**')
     }
 
     project.ext.allSS.each { ss ->
@@ -135,6 +149,17 @@
     artifacts.add('archives', sourcesJarTask);
 }
 
+// TODO make this generic for all projects
+afterEvaluate {
+    def originalTask = tasks['packageDebugAndroidTest']
+    tasks['assembleDebugAndroidTest'].doLast {
+        copy {
+            from(originalTask.outputFile)
+            into(rootProject.ext.testApkDistOut)
+        }
+    }
+}
+
 uploadArchives {
     repositories {
         mavenDeployer {
diff --git a/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java b/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java
index 6d98c97..07cc602 100644
--- a/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java
+++ b/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java
@@ -19,7 +19,7 @@
 import android.view.View;
 
 /**
- * Compatibility implementation for {@link android.animation.Animator}.
+ * Compatibility implementation for {@code android.animation.ValueAnimator}.
  *
  * @hide
  */
diff --git a/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java b/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java
index 4809618..fe0163d 100644
--- a/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java
+++ b/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java
@@ -27,19 +27,19 @@
 
     public static void setTint(Drawable drawable, int tint) {
         if (drawable instanceof DrawableWrapper) {
-            ((DrawableWrapper) drawable).setTint(tint);
+            ((DrawableWrapper) drawable).setCompatTint(tint);
         }
     }
 
     public static void setTintList(Drawable drawable, ColorStateList tint) {
         if (drawable instanceof DrawableWrapper) {
-            ((DrawableWrapper) drawable).setTintList(tint);
+            ((DrawableWrapper) drawable).setCompatTintList(tint);
         }
     }
 
     public static void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
         if (drawable instanceof DrawableWrapper) {
-            ((DrawableWrapper) drawable).setTintMode(tintMode);
+            ((DrawableWrapper) drawable).setCompatTintMode(tintMode);
         }
     }
 
diff --git a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java
index 1073f34..edbe5ad 100644
--- a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java
+++ b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java
@@ -28,11 +28,11 @@
  */
 public interface DrawableWrapper {
 
-    void setTint(int tint);
+    void setCompatTint(int tint);
 
-    void setTintList(ColorStateList tint);
+    void setCompatTintList(ColorStateList tint);
 
-    void setTintMode(PorterDuff.Mode tintMode);
+    void setCompatTintMode(PorterDuff.Mode tintMode);
 
     Drawable getWrappedDrawable();
 
diff --git a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
index 9293520..300e2e8 100644
--- a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
+++ b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
@@ -89,7 +89,8 @@
 
     @Override
     public boolean isStateful() {
-        return (mTintList != null && mTintList.isStateful()) || mDrawable.isStateful();
+        final ColorStateList tintList = isCompatTintEnabled() ? mTintList : null;
+        return (tintList != null && tintList.isStateful()) || mDrawable.isStateful();
     }
 
     @Override
@@ -188,30 +189,38 @@
     }
 
     @Override
-    public void setTint(int tint) {
-        setTintList(ColorStateList.valueOf(tint));
+    public void setCompatTint(int tint) {
+        setCompatTintList(ColorStateList.valueOf(tint));
     }
 
     @Override
-    public void setTintList(ColorStateList tint) {
-        mTintList = tint;
-        updateTint(getState());
+    public void setCompatTintList(ColorStateList tint) {
+        if (mTintList != tint) {
+            mTintList = tint;
+            updateTint(getState());
+        }
     }
 
     @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
-        mTintMode = tintMode;
-        updateTint(getState());
+    public void setCompatTintMode(PorterDuff.Mode tintMode) {
+        if (mTintMode != tintMode) {
+            mTintMode = tintMode;
+            updateTint(getState());
+        }
     }
 
     private boolean updateTint(int[] state) {
+        if (!isCompatTintEnabled()) {
+            // If compat tinting is not enabled, fail fast
+            return false;
+        }
+
         if (mTintList != null && mTintMode != null) {
             final int color = mTintList.getColorForState(state, mTintList.getDefaultColor());
-            final PorterDuff.Mode mode = mTintMode;
-            if (!mColorFilterSet || color != mCurrentColor || mode != mCurrentMode) {
-                setColorFilter(color, mode);
+            if (!mColorFilterSet || color != mCurrentColor || mTintMode != mCurrentMode) {
+                setColorFilter(color, mTintMode);
                 mCurrentColor = color;
-                mCurrentMode = mode;
+                mCurrentMode = mTintMode;
                 mColorFilterSet = true;
                 return true;
             }
@@ -236,13 +245,26 @@
         if (mDrawable != null) {
             mDrawable.setCallback(null);
         }
+        mDrawable = null;
+
+        if (drawable != null) {
+            // Copy over the bounds from the drawable
+            setBounds(drawable.getBounds());
+            // Set ourselves as the callback for invalidations
+            drawable.setCallback(this);
+        } else {
+            // Clear our bounds
+            setBounds(0, 0, 0, 0);
+        }
 
         mDrawable = drawable;
 
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
         // Invalidate ourselves
         invalidateSelf();
     }
+
+    protected boolean isCompatTintEnabled() {
+        // It's enabled by default on Donut
+        return true;
+    }
 }
diff --git a/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java b/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java
index f49eb2b..d03287fe 100644
--- a/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java
+++ b/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.media.AudioManager;
 
-public class MediaSessionCompatApi8 {
+class MediaSessionCompatApi8 {
     public static void registerMediaButtonEventReceiver(Context context, ComponentName mbr) {
         AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         am.registerMediaButtonEventReceiver(mbr);
diff --git a/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java b/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java
index 429e864..61c9a03 100644
--- a/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java
+++ b/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java
@@ -87,4 +87,9 @@
     public static int getFinalY(Object scroller) {
         return ((OverScroller) scroller).getFinalY();
     }
+
+    public static boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+            int minY, int maxY) {
+        return ((OverScroller) scroller).springBack(startX, startY, minX, maxX, minY, maxY);
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java b/v4/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
similarity index 61%
copy from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
copy to v4/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
index c84fda0..fa6af47 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
+++ b/v4/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v4.content;
 
-import android.graphics.Rect;
+import android.os.AsyncTask;
+
+import java.util.concurrent.Executor;
 
 /**
+ * Implementation of parallel executor compatibility that can call Honeycomb APIs.
  * @hide
  */
-public interface FitWindowsViewGroup {
-
-    public interface OnFitSystemWindowsListener {
-        void onFitSystemWindows(Rect insets);
+class ExecutorCompatHoneycomb {
+    public static Executor getParallelExecutor() {
+        return AsyncTask.THREAD_POOL_EXECUTOR;
     }
-
-    public void setOnFitSystemWindowsListener(OnFitSystemWindowsListener listener);
-
 }
diff --git a/v4/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java b/v4/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java
new file mode 100644
index 0000000..780345c
--- /dev/null
+++ b/v4/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java
@@ -0,0 +1,32 @@
+/*
+ * 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.view;
+
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * Helper for accessing newer features in View introduced in ICS Mr1.
+ */
+class ViewCompatICSMr1 {
+    public static boolean hasOnClickListeners(View v) {
+        return v.hasOnClickListeners();
+    }
+}
diff --git a/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java b/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
index de644e6..3378e1e 100644
--- a/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
+++ b/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
@@ -25,7 +25,7 @@
 import android.os.Bundle;
 import android.os.ResultReceiver;
 
-public class MediaSessionCompatApi14 {
+class MediaSessionCompatApi14 {
     /***** RemoteControlClient States, we only need none as the others were public *******/
     final static int RCC_PLAYSTATE_NONE = 0;
 
@@ -224,7 +224,7 @@
         }
     }
 
-    public static interface Callback {
+    static interface Callback {
         public void onCommand(String command, Bundle extras, ResultReceiver cb);
 
         public boolean onMediaButtonEvent(Intent mediaButtonIntent);
diff --git a/v4/ics/android/support/v4/view/ViewParentCompatICS.java b/v4/ics/android/support/v4/view/ViewParentCompatICS.java
index 251de0e..f9fc5a5 100644
--- a/v4/ics/android/support/v4/view/ViewParentCompatICS.java
+++ b/v4/ics/android/support/v4/view/ViewParentCompatICS.java
@@ -23,7 +23,7 @@
 /**
  * ICS-specific ViewParent API implementation.
  */
-public class ViewParentCompatICS {
+class ViewParentCompatICS {
     public static boolean requestSendAccessibilityEvent(
             ViewParent parent, View child, AccessibilityEvent event) {
         return parent.requestSendAccessibilityEvent(child, event);
diff --git a/v4/java/android/support/v4/animation/AnimatorCompatHelper.java b/v4/java/android/support/v4/animation/AnimatorCompatHelper.java
index 8fa3679..6ebe5c8 100644
--- a/v4/java/android/support/v4/animation/AnimatorCompatHelper.java
+++ b/v4/java/android/support/v4/animation/AnimatorCompatHelper.java
@@ -19,9 +19,12 @@
 import android.os.Build;
 import android.view.View;
 
-abstract public class AnimatorCompatHelper {
+/**
+ * @hide
+ */
+public final class AnimatorCompatHelper {
 
-    static AnimatorProvider IMPL;
+    private final static AnimatorProvider IMPL;
 
     static {
         if (Build.VERSION.SDK_INT >= 12) {
@@ -35,9 +38,7 @@
         return IMPL.emptyValueAnimator();
     }
 
-    AnimatorCompatHelper() {
-
-    }
+    private AnimatorCompatHelper() {}
 
     public static void clearInterpolator(View view) {
         IMPL.clearInterpolator(view);
diff --git a/v4/java/android/support/v4/app/FragmentActivity.java b/v4/java/android/support/v4/app/FragmentActivity.java
index 1dd6d01..59881a2 100644
--- a/v4/java/android/support/v4/app/FragmentActivity.java
+++ b/v4/java/android/support/v4/app/FragmentActivity.java
@@ -27,6 +27,7 @@
 import android.os.Parcelable;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.v4.media.session.MediaControllerCompat;
 import android.support.v4.util.SimpleArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -124,6 +125,8 @@
         SimpleArrayMap<String, LoaderManager> loaders;
     }
 
+    MediaControllerCompat mMediaController;
+
     // ------------------------------------------------------------------------
     // HOOKS INTO ACTIVITY
     // ------------------------------------------------------------------------
@@ -169,6 +172,39 @@
     }
 
     /**
+     * Sets a {@link MediaControllerCompat} for later retrieval via
+     * {@link #getSupportMediaController()}.
+     *
+     * <p>On API 21 and later, this controller will be tied to the window of the activity and
+     * media key and volume events which are received while the Activity is in the foreground
+     * will be forwarded to the controller and used to invoke transport controls or adjust the
+     * volume. Prior to API 21, the global handling of media key and volume events through an
+     * active {@link android.support.v4.media.session.MediaSessionCompat} and media button receiver
+     * will still be respected.</p>
+     *
+     * @param mediaController The controller for the session which should receive
+     *     media keys and volume changes on API 21 and later.
+     * @see #setMediaController(android.media.session.MediaController)
+     */
+    final public void setSupportMediaController(MediaControllerCompat mediaController) {
+        mMediaController = mediaController;
+        if (android.os.Build.VERSION.SDK_INT >= 21) {
+            ActivityCompat21.setMediaController(this, mediaController.getMediaController());
+        }
+    }
+
+    /**
+     * Retrieves the current {@link MediaControllerCompat} for sending media key and volume events.
+     *
+     * @return The controller which should receive events.
+     * @see #setSupportMediaController(android.support.v4.media.session.MediaController)
+     * @see #getMediaController()
+     */
+    final public MediaControllerCompat getSupportMediaController() {
+        return mMediaController;
+    }
+
+    /**
      * Reverses the Activity Scene entry Transition and triggers the calling Activity
      * to reverse its exit Transition. When the exit Transition completes,
      * {@link #finish()} is called. If no entry Transition was used, finish() is called
diff --git a/v4/java/android/support/v4/app/FragmentManager.java b/v4/java/android/support/v4/app/FragmentManager.java
index adf8892..50bc88b 100644
--- a/v4/java/android/support/v4/app/FragmentManager.java
+++ b/v4/java/android/support/v4/app/FragmentManager.java
@@ -52,6 +52,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -414,8 +415,9 @@
 
 
     static class AnimateOnHWLayerIfNeededListener implements AnimationListener {
+        private AnimationListener mOrignalListener = null;
         private boolean mShouldRunOnHWLayer = false;
-        private View mView;
+        private View mView = null;
         public AnimateOnHWLayerIfNeededListener(final View v, Animation anim) {
             if (v == null || anim == null) {
                 return;
@@ -423,24 +425,38 @@
             mView = v;
         }
 
+        public AnimateOnHWLayerIfNeededListener(final View v, Animation anim,
+                AnimationListener listener) {
+            if (v == null || anim == null) {
+                return;
+            }
+            mOrignalListener = listener;
+            mView = v;
+        }
+
         @Override
         @CallSuper
         public void onAnimationStart(Animation animation) {
-            mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
-            if (mShouldRunOnHWLayer) {
-                mView.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_HARDWARE, null);
-                    }
-                });
+            if (mView != null) {
+                mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
+                if (mShouldRunOnHWLayer) {
+                    mView.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_HARDWARE, null);
+                        }
+                    });
+                }
+            }
+            if (mOrignalListener != null) {
+                mOrignalListener.onAnimationStart(animation);
             }
         }
 
         @Override
         @CallSuper
         public void onAnimationEnd(Animation animation) {
-            if (mShouldRunOnHWLayer) {
+            if (mView != null && mShouldRunOnHWLayer) {
                 mView.post(new Runnable() {
                     @Override
                     public void run() {
@@ -448,10 +464,16 @@
                     }
                 });
             }
+            if (mOrignalListener != null) {
+                mOrignalListener.onAnimationEnd(animation);
+            }
         }
 
         @Override
         public void onAnimationRepeat(Animation animation) {
+            if (mOrignalListener != null) {
+                mOrignalListener.onAnimationRepeat(animation);
+            }
         }
     }
 
@@ -476,6 +498,8 @@
     FragmentController mController;
     FragmentContainer mContainer;
     Fragment mParent;
+
+    static Field sAnimationListenerField = null;
     
     boolean mNeedMenuInvalidate;
     boolean mStateSaved;
@@ -509,7 +533,8 @@
     }
 
     static boolean shouldRunOnHWLayer(View v, Animation anim) {
-        return ViewCompat.getLayerType(v) == ViewCompat.LAYER_TYPE_NONE
+        return Build.VERSION.SDK_INT >= 19
+                && ViewCompat.getLayerType(v) == ViewCompat.LAYER_TYPE_NONE
                 && ViewCompat.hasOverlappingRendering(v)
                 && modifiesAlpha(anim);
     }
@@ -914,7 +939,23 @@
             return;
         }
         if (shouldRunOnHWLayer(v, anim)) {
-            anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(v, anim));
+            AnimationListener originalListener = null;
+            try {
+                if (sAnimationListenerField == null) {
+                    sAnimationListenerField = Animation.class.getDeclaredField("mListener");
+                    sAnimationListenerField.setAccessible(true);
+                }
+                originalListener = (AnimationListener) sAnimationListenerField.get(anim);
+            } catch (NoSuchFieldException e) {
+                Log.e(TAG, "No field with the name mListener is found in Animation class", e);
+            } catch (IllegalAccessException e) {
+                Log.e(TAG, "Cannot access Animation's mListener field", e);
+            }
+            // If there's already a listener set on the animation, we need wrap the new listener
+            // around the existing listener, so that they will both get animation listener
+            // callbacks.
+            anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(v, anim,
+                    originalListener));
         }
     }
 
diff --git a/v4/java/android/support/v4/content/ContextCompat.java b/v4/java/android/support/v4/content/ContextCompat.java
index b8029d1..29629e7 100644
--- a/v4/java/android/support/v4/content/ContextCompat.java
+++ b/v4/java/android/support/v4/content/ContextCompat.java
@@ -403,7 +403,7 @@
      *
      * @see android.content.Context.getFilesDir
      */
-    public final File getNoBackupFilesDir(Context context) {
+    public static File getNoBackupFilesDir(Context context) {
         final int version = Build.VERSION.SDK_INT;
         if (version >= 21) {
             return ContextCompatApi21.getNoBackupFilesDir(context);
@@ -428,7 +428,7 @@
      *
      * @return The path of the directory holding application code cache files.
      */
-    public final File getCodeCacheDir(Context context) {
+    public static File getCodeCacheDir(Context context) {
         final int version = Build.VERSION.SDK_INT;
         if (version >= 21) {
             return ContextCompatApi21.getCodeCacheDir(context);
diff --git a/v4/java/android/support/v4/content/ParallelExecutorCompat.java b/v4/java/android/support/v4/content/ParallelExecutorCompat.java
new file mode 100644
index 0000000..c23470b
--- /dev/null
+++ b/v4/java/android/support/v4/content/ParallelExecutorCompat.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.content;
+
+import android.os.Build;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Helper for accessing a shared parallel Executor instance
+ * introduced after API level 4 in a backwards compatible fashion.
+ */
+public class ParallelExecutorCompat {
+    public static Executor getParallelExecutor() {
+        if (Build.VERSION.SDK_INT >= 11) {
+            // From API 11 onwards, return AsyncTask.THREAD_POOL_EXECUTOR
+            return ExecutorCompatHoneycomb.getParallelExecutor();
+        } else {
+            return ModernAsyncTask.THREAD_POOL_EXECUTOR;
+        }
+    }
+}
diff --git a/v4/java/android/support/v4/content/res/ResourcesCompat.java b/v4/java/android/support/v4/content/res/ResourcesCompat.java
index 252977b..ce5f658 100644
--- a/v4/java/android/support/v4/content/res/ResourcesCompat.java
+++ b/v4/java/android/support/v4/content/res/ResourcesCompat.java
@@ -16,11 +16,18 @@
 
 package android.support.v4.content.res;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
+import android.support.annotation.ColorInt;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import static android.os.Build.VERSION.SDK_INT;
 
 /**
  * Helper for accessing features in {@link android.content.res.Resources}
@@ -45,11 +52,11 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *         not exist.
      */
+    @Nullable
     @SuppressWarnings("deprecation")
-    public static Drawable getDrawable(Resources res, int id, Theme theme)
-            throws NotFoundException {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
+    public static Drawable getDrawable(@NonNull Resources res, @DrawableRes int id,
+            @Nullable Theme theme) throws NotFoundException {
+        if (SDK_INT >= 21) {
             return ResourcesCompatApi21.getDrawable(res, id, theme);
         } else {
             return res.getDrawable(id);
@@ -65,7 +72,7 @@
      * this method simply calls through to {@link Resources#getDrawable(int)}.
      * <p>
      * Prior to API level 21, the theme will not be applied and this method
-     * calls through to Resources.getDrawableForDensity(int, int).
+     * calls through to Resources#getDrawableForDensity(int, int).
      *
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
@@ -76,18 +83,76 @@
      *              {@code null}.
      * @return Drawable An object that can be used to draw this resource.
      * @throws NotFoundException Throws NotFoundException if the given ID does
-     *             not exist.
+     *         not exist.
      */
+    @Nullable
     @SuppressWarnings("deprecation")
-    public static Drawable getDrawableForDensity(Resources res, int id, int density, Theme theme)
-            throws NotFoundException {
-        final int version = Build.VERSION.SDK_INT;
-        if (version >= 21) {
+    public static Drawable getDrawableForDensity(@NonNull Resources res, @DrawableRes int id,
+            int density, @Nullable Theme theme) throws NotFoundException {
+        if (SDK_INT >= 21) {
             return ResourcesCompatApi21.getDrawableForDensity(res, id, density, theme);
-        } else if (version >= 15) {
+        } else if (SDK_INT >= 15) {
             return ResourcesCompatIcsMr1.getDrawableForDensity(res, id, density);
         } else {
             return res.getDrawable(id);
         }
     }
+
+    /**
+     * Returns a themed color integer associated with a particular resource ID.
+     * If the resource holds a complex {@link ColorStateList}, then the default
+     * color from the set is returned.
+     * <p>
+     * Prior to API level 23, the theme will not be applied and this method
+     * calls through to {@link Resources#getColor(int)}.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @param theme The theme used to style the color attributes, may be
+     *              {@code null}.
+     * @return A single color value in the form {@code 0xAARRGGBB}.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    @ColorInt
+    @SuppressWarnings("deprecation")
+    public static int getColor(@NonNull Resources res, @ColorRes int id, @Nullable Theme theme)
+            throws NotFoundException {
+        if (SDK_INT >= 23) {
+            return ResourcesCompatApi23.getColor(res, id, theme);
+        } else {
+            return res.getColor(id);
+        }
+    }
+
+    /**
+     * Returns a themed color state list associated with a particular resource
+     * ID. The resource may contain either a single raw color value or a
+     * complex {@link ColorStateList} holding multiple possible colors.
+     * <p>
+     * Prior to API level 23, the theme will not be applied and this method
+     * calls through to {@link Resources#getColorStateList(int)}.
+     *
+     * @param id The desired resource identifier of a {@link ColorStateList},
+     *           as generated by the aapt tool. This integer encodes the
+     *           package, type, and resource entry. The value 0 is an invalid
+     *           identifier.
+     * @param theme The theme used to style the color attributes, may be
+     *              {@code null}.
+     * @return A themed ColorStateList object containing either a single solid
+     *         color or multiple colors that can be selected based on a state.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    @Nullable
+    @SuppressWarnings("deprecation")
+    public static ColorStateList getColorStateList(@NonNull Resources res, @ColorRes int id,
+            @Nullable Theme theme) throws NotFoundException {
+        if (SDK_INT >= 23) {
+            return ResourcesCompatApi23.getColorStateList(res, id, theme);
+        } else {
+            return res.getColorStateList(id);
+        }
+    }
 }
diff --git a/v4/java/android/support/v4/graphics/ColorUtils.java b/v4/java/android/support/v4/graphics/ColorUtils.java
index aac809b..4d9d9b2 100644
--- a/v4/java/android/support/v4/graphics/ColorUtils.java
+++ b/v4/java/android/support/v4/graphics/ColorUtils.java
@@ -17,6 +17,10 @@
 package android.support.v4.graphics;
 
 import android.graphics.Color;
+import android.support.annotation.ColorInt;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
 
 /**
  * A set of color-related utility methods, building upon those available in {@code Color}.
@@ -24,14 +28,14 @@
 public class ColorUtils {
 
     private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
-    private static final int MIN_ALPHA_SEARCH_PRECISION = 10;
+    private static final int MIN_ALPHA_SEARCH_PRECISION = 1;
 
     private ColorUtils() {}
 
     /**
      * Composite two potentially translucent colors over each other and returns the result.
      */
-    public static int compositeColors(int foreground, int background) {
+    public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
         int bgAlpha = Color.alpha(background);
         int fgAlpha = Color.alpha(foreground);
         int a = compositeAlpha(fgAlpha, bgAlpha);
@@ -57,10 +61,13 @@
 
     /**
      * Returns the luminance of a color.
-     *
-     * Formula defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+     * <p>
+     * Formula defined
+     * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef">here</a>.
+     * </p>
      */
-    public static double calculateLuminance(int color) {
+    @FloatRange(from = 0.0, to = 1.0)
+    public static double calculateLuminance(@ColorInt int color) {
         double red = Color.red(color) / 255d;
         red = red < 0.03928 ? red / 12.92 : Math.pow((red + 0.055) / 1.055, 2.4);
 
@@ -80,9 +87,10 @@
      * Formula defined
      * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef">here</a>.
      */
-    public static double calculateContrast(int foreground, int background) {
+    public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) {
         if (Color.alpha(background) != 255) {
-            throw new IllegalArgumentException("background can not be translucent");
+            throw new IllegalArgumentException("background can not be translucent: #"
+                    + Integer.toHexString(background));
         }
         if (Color.alpha(foreground) < 255) {
             // If the foreground is translucent, composite the foreground over the background
@@ -106,10 +114,11 @@
      * @param minContrastRatio the minimum contrast ratio.
      * @return the alpha value in the range 0-255, or -1 if no value could be calculated.
      */
-    public static int calculateMinimumAlpha(int foreground, int background,
+    public static int calculateMinimumAlpha(@ColorInt int foreground, @ColorInt int background,
             float minContrastRatio) {
         if (Color.alpha(background) != 255) {
-            throw new IllegalArgumentException("background can not be translucent");
+            throw new IllegalArgumentException("background can not be translucent: #"
+                    + Integer.toHexString(background));
         }
 
         // First lets check that a fully opaque foreground has sufficient contrast
@@ -158,7 +167,9 @@
      * @param b   blue component value [0..255]
      * @param hsl 3 element array which holds the resulting HSL components.
      */
-    public static void RGBToHSL(int r, int g, int b, float[] hsl) {
+    public static void RGBToHSL(@IntRange(from = 0x0, to = 0xFF) int r,
+            @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+            @NonNull float[] hsl) {
         final float rf = r / 255f;
         final float gf = g / 255f;
         final float bf = b / 255f;
@@ -206,7 +217,7 @@
      * @param color the ARGB color to convert. The alpha component is ignored.
      * @param hsl 3 element array which holds the resulting HSL components.
      */
-    public static void colorToHSL(int color, float[] hsl) {
+    public static void colorToHSL(@ColorInt int color, @NonNull float[] hsl) {
         RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hsl);
     }
 
@@ -222,7 +233,8 @@
      * @param hsl 3 element array which holds the input HSL components.
      * @return the resulting RGB color
      */
-    public static int HSLToColor(float[] hsl) {
+    @ColorInt
+    public static int HSLToColor(@NonNull float[] hsl) {
         final float h = hsl[0];
         final float s = hsl[1];
         final float l = hsl[2];
@@ -279,7 +291,9 @@
     /**
      * Set the alpha component of {@code color} to be {@code alpha}.
      */
-    public static int setAlphaComponent(int color, int alpha) {
+    @ColorInt
+    public static int setAlphaComponent(@ColorInt int color,
+            @IntRange(from = 0x0, to = 0xFF) int alpha) {
         if (alpha < 0 || alpha > 255) {
             throw new IllegalArgumentException("alpha must be between 0 and 255.");
         }
diff --git a/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java b/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
index 88b5f4a..64ae075 100644
--- a/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
+++ b/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
@@ -123,7 +123,7 @@
         @Override
         public int getLayoutDirection(Drawable drawable) {
             final int dir = DrawableCompatJellybeanMr1.getLayoutDirection(drawable);
-            return dir < 0 ? dir : ViewCompat.LAYOUT_DIRECTION_LTR;
+            return dir >= 0 ? dir : ViewCompat.LAYOUT_DIRECTION_LTR;
         }
     }
 
diff --git a/v4/java/android/support/v4/media/MediaBrowserCompat.java b/v4/java/android/support/v4/media/MediaBrowserCompat.java
new file mode 100644
index 0000000..dcce7f5
--- /dev/null
+++ b/v4/java/android/support/v4/media/MediaBrowserCompat.java
@@ -0,0 +1,1243 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.BundleCompat;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.os.ResultReceiver;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.support.v4.media.MediaBrowserProtocol.*;
+
+/**
+ * Browses media content offered by a {@link MediaBrowserServiceCompat}.
+ * <p>
+ * This object is not thread-safe. All calls should happen on the thread on which the browser
+ * was constructed.
+ * </p>
+ */
+public final class MediaBrowserCompat {
+    private static final String TAG = "MediaBrowserCompat";
+
+    private final MediaBrowserImpl mImpl;
+
+    /**
+     * Creates a media browser for the specified media browse service.
+     *
+     * @param context The context.
+     * @param serviceComponent The component name of the media browse service.
+     * @param callback The connection callback.
+     * @param rootHints An optional bundle of service-specific arguments to send
+     * to the media browse service when connecting and retrieving the root id
+     * for browsing, or null if none.  The contents of this bundle may affect
+     * the information returned when browsing.
+     */
+    public MediaBrowserCompat(Context context, ComponentName serviceComponent,
+            ConnectionCallback callback, Bundle rootHints) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            mImpl = new MediaBrowserImplApi23(context, serviceComponent, callback, rootHints);
+        } else if (android.os.Build.VERSION.SDK_INT >= 21) {
+            mImpl = new MediaBrowserImplApi21(context, serviceComponent, callback, rootHints);
+        } else {
+            mImpl = new MediaBrowserImplBase(context, serviceComponent, callback, rootHints);
+        }
+    }
+
+    /**
+     * Connects to the media browse service.
+     * <p>
+     * The connection callback specified in the constructor will be invoked
+     * when the connection completes or fails.
+     * </p>
+     */
+    public void connect() {
+        mImpl.connect();
+    }
+
+    /**
+     * Disconnects from the media browse service.
+     * After this, no more callbacks will be received.
+     */
+    public void disconnect() {
+        mImpl.disconnect();
+    }
+
+    /**
+     * Returns whether the browser is connected to the service.
+     */
+    public boolean isConnected() {
+        return mImpl.isConnected();
+    }
+
+    /**
+     * Gets the service component that the media browser is connected to.
+     */
+    public @NonNull
+    ComponentName getServiceComponent() {
+        return mImpl.getServiceComponent();
+    }
+
+    /**
+     * Gets the root id.
+     * <p>
+     * Note that the root id may become invalid or change when when the
+     * browser is disconnected.
+     * </p>
+     *
+     * @throws IllegalStateException if not connected.
+     */
+    public @NonNull String getRoot() {
+        return mImpl.getRoot();
+    }
+
+    /**
+     * Gets any extras for the media service.
+     *
+     * @throws IllegalStateException if not connected.
+     */
+    public @Nullable
+    Bundle getExtras() {
+        return mImpl.getExtras();
+    }
+
+    /**
+     * Gets the media session token associated with the media browser.
+     * <p>
+     * Note that the session token may become invalid or change when when the
+     * browser is disconnected.
+     * </p>
+     *
+     * @return The session token for the browser, never null.
+     *
+     * @throws IllegalStateException if not connected.
+     */
+     public @NonNull MediaSessionCompat.Token getSessionToken() {
+        return mImpl.getSessionToken();
+    }
+
+    /**
+     * Queries for information about the media items that are contained within
+     * the specified id and subscribes to receive updates when they change.
+     * <p>
+     * The list of subscriptions is maintained even when not connected and is
+     * restored after reconnection. It is ok to subscribe while not connected
+     * but the results will not be returned until the connection completes.
+     * </p>
+     * <p>
+     * If the id is already subscribed with a different callback then the new
+     * callback will replace the previous one and the child data will be
+     * reloaded.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose list of children
+     *            will be subscribed.
+     * @param callback The callback to receive the list of children.
+     */
+    public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+        mImpl.subscribe(parentId, callback);
+    }
+
+    /**
+     * Unsubscribes for changes to the children of the specified media id.
+     * <p>
+     * The query callback will no longer be invoked for results associated with
+     * this id once this method returns.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose list of children
+     * will be unsubscribed.
+     */
+    public void unsubscribe(@NonNull String parentId) {
+        mImpl.unsubscribe(parentId);
+    }
+
+    /**
+     * Retrieves a specific {@link MediaItem} from the connected service. Not
+     * all services may support this, so falling back to subscribing to the
+     * parent's id should be used when unavailable.
+     *
+     * @param mediaId The id of the item to retrieve.
+     * @param cb The callback to receive the result on.
+     */
+    public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
+        mImpl.getItem(mediaId, cb);
+    }
+
+    public static class MediaItem implements Parcelable {
+        private final int mFlags;
+        private final MediaDescriptionCompat mDescription;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
+        public @interface Flags { }
+
+        /**
+         * Flag: Indicates that the item has children of its own.
+         */
+        public static final int FLAG_BROWSABLE = 1 << 0;
+
+        /**
+         * Flag: Indicates that the item is playable.
+         * <p>
+         * The id of this item may be passed to
+         * {@link MediaControllerCompat.TransportControls#playFromMediaId(String, Bundle)}
+         * to start playing it.
+         * </p>
+         */
+        public static final int FLAG_PLAYABLE = 1 << 1;
+
+        /**
+         * Create a new MediaItem for use in browsing media.
+         * @param description The description of the media, which must include a
+         *            media id.
+         * @param flags The flags for this item.
+         */
+        public MediaItem(@NonNull MediaDescriptionCompat description, @Flags int flags) {
+            if (description == null) {
+                throw new IllegalArgumentException("description cannot be null");
+            }
+            if (TextUtils.isEmpty(description.getMediaId())) {
+                throw new IllegalArgumentException("description must have a non-empty media id");
+            }
+            mFlags = flags;
+            mDescription = description;
+        }
+
+        /**
+         * Private constructor.
+         */
+        private MediaItem(Parcel in) {
+            mFlags = in.readInt();
+            mDescription = MediaDescriptionCompat.CREATOR.createFromParcel(in);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(mFlags);
+            mDescription.writeToParcel(out, flags);
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("MediaItem{");
+            sb.append("mFlags=").append(mFlags);
+            sb.append(", mDescription=").append(mDescription);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        public static final Parcelable.Creator<MediaItem> CREATOR =
+                new Parcelable.Creator<MediaItem>() {
+                    @Override
+                    public MediaItem createFromParcel(Parcel in) {
+                        return new MediaItem(in);
+                    }
+
+                    @Override
+                    public MediaItem[] newArray(int size) {
+                        return new MediaItem[size];
+                    }
+                };
+
+        /**
+         * Gets the flags of the item.
+         */
+        public @Flags int getFlags() {
+            return mFlags;
+        }
+
+        /**
+         * Returns whether this item is browsable.
+         * @see #FLAG_BROWSABLE
+         */
+        public boolean isBrowsable() {
+            return (mFlags & FLAG_BROWSABLE) != 0;
+        }
+
+        /**
+         * Returns whether this item is playable.
+         * @see #FLAG_PLAYABLE
+         */
+        public boolean isPlayable() {
+            return (mFlags & FLAG_PLAYABLE) != 0;
+        }
+
+        /**
+         * Returns the description of the media.
+         */
+        public @NonNull MediaDescriptionCompat getDescription() {
+            return mDescription;
+        }
+
+        /**
+         * Returns the media id for this item.
+         */
+        public @NonNull String getMediaId() {
+            return mDescription.getMediaId();
+        }
+    }
+
+
+    /**
+     * Callbacks for connection related events.
+     */
+    public static class ConnectionCallback {
+        final Object mConnectionCallbackObj;
+
+        public ConnectionCallback() {
+            if (android.os.Build.VERSION.SDK_INT >= 21) {
+                mConnectionCallbackObj =
+                        MediaBrowserCompatApi21.createConnectionCallback(new StubApi21());
+            } else {
+                mConnectionCallbackObj = null;
+            }
+        }
+
+        /**
+         * Invoked after {@link MediaBrowserCompat#connect()} when the request has successfully
+         * completed.
+         */
+        public void onConnected() {
+        }
+
+        /**
+         * Invoked when the client is disconnected from the media browser.
+         */
+        public void onConnectionSuspended() {
+        }
+
+        /**
+         * Invoked when the connection to the media browser failed.
+         */
+        public void onConnectionFailed() {
+        }
+
+
+        private class StubApi21 implements MediaBrowserCompatApi21.ConnectionCallback {
+            @Override
+            public void onConnected() {
+                ConnectionCallback.this.onConnected();
+            }
+
+            @Override
+            public void onConnectionSuspended() {
+                ConnectionCallback.this.onConnectionSuspended();
+            }
+
+            @Override
+            public void onConnectionFailed() {
+                ConnectionCallback.this.onConnectionFailed();
+            }
+        }
+    }
+
+    /**
+     * Callbacks for subscription related events.
+     */
+    public static abstract class SubscriptionCallback {
+        final Object mSubscriptionCallbackObj;
+
+        public SubscriptionCallback() {
+            if (android.os.Build.VERSION.SDK_INT >= 21) {
+                mSubscriptionCallbackObj =
+                        MediaBrowserCompatApi21.createSubscriptionCallback(new StubApi21());
+            } else {
+                mSubscriptionCallbackObj = null;
+            }
+        }
+
+        /**
+         * Called when the list of children is loaded or updated.
+         *
+         * @param parentId The media id of the parent media item.
+         * @param children The children which were loaded, or null if the id is invalid.
+         */
+        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
+        }
+
+        /**
+         * Called when the id doesn't exist or other errors in subscribing.
+         * <p>
+         * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
+         * called, because some errors may heal themselves.
+         * </p>
+         *
+         * @param parentId The media id of the parent media item whose children could
+         * not be loaded.
+         */
+        public void onError(@NonNull String parentId) {
+        }
+
+        private class StubApi21 implements MediaBrowserCompatApi21.SubscriptionCallback {
+            @Override
+            public void onChildrenLoaded(@NonNull String parentId, @NonNull List<Parcel> children) {
+                List<MediaBrowserCompat.MediaItem> mediaItems = null;
+                if (children != null) {
+                    mediaItems = new ArrayList<>();
+                    for (Parcel parcel : children) {
+                        parcel.setDataPosition(0);
+                        mediaItems.add(
+                                MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(parcel));
+                        parcel.recycle();
+                    }
+                }
+                SubscriptionCallback.this.onChildrenLoaded(parentId, mediaItems);
+            }
+
+            @Override
+            public void onError(@NonNull String parentId) {
+                SubscriptionCallback.this.onError(parentId);
+            }
+        }
+    }
+
+    /**
+     * Callback for receiving the result of {@link #getItem}.
+     */
+    public static abstract class ItemCallback {
+        final Object mItemCallbackObj;
+
+        public ItemCallback() {
+            if (android.os.Build.VERSION.SDK_INT >= 23) {
+                mItemCallbackObj = MediaBrowserCompatApi23.createItemCallback(new StubApi23());
+            } else {
+                mItemCallbackObj = null;
+            }
+        }
+
+        /**
+         * Called when the item has been returned by the browser service.
+         *
+         * @param item The item that was returned or null if it doesn't exist.
+         */
+        public void onItemLoaded(MediaItem item) {
+        }
+
+        /**
+         * Called when the item doesn't exist or there was an error retrieving it.
+         *
+         * @param itemId The media id of the media item which could not be loaded.
+         */
+        public void onError(@NonNull String itemId) {
+        }
+
+        private class StubApi23 implements MediaBrowserCompatApi23.ItemCallback {
+            @Override
+            public void onItemLoaded(Parcel itemParcel) {
+                itemParcel.setDataPosition(0);
+                MediaItem item = MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(itemParcel);
+                itemParcel.recycle();
+                ItemCallback.this.onItemLoaded(item);
+            }
+
+            @Override
+            public void onError(@NonNull String itemId) {
+                ItemCallback.this.onError(itemId);
+            }
+        }
+    }
+
+    interface MediaBrowserImpl {
+        void connect();
+        void disconnect();
+        boolean isConnected();
+        ComponentName getServiceComponent();
+        @NonNull String getRoot();
+        @Nullable Bundle getExtras();
+        @NonNull MediaSessionCompat.Token getSessionToken();
+        void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback);
+        void unsubscribe(@NonNull String parentId);
+        void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb);
+    }
+
+    static class MediaBrowserImplBase implements MediaBrowserImpl {
+        private static final boolean DBG = false;
+
+        private static final int CONNECT_STATE_DISCONNECTED = 0;
+        private static final int CONNECT_STATE_CONNECTING = 1;
+        private static final int CONNECT_STATE_CONNECTED = 2;
+        private static final int CONNECT_STATE_SUSPENDED = 3;
+
+        private final Context mContext;
+        private final ComponentName mServiceComponent;
+        private final ConnectionCallback mCallback;
+        private final Bundle mRootHints;
+        private final CallbackHandler mHandler = new CallbackHandler();
+        private final ArrayMap<String,Subscription> mSubscriptions = new ArrayMap<>();
+
+        private int mState = CONNECT_STATE_DISCONNECTED;
+        private MediaServiceConnection mServiceConnection;
+        private ServiceBinderWrapper mServiceBinderWrapper;
+        private Messenger mCallbacksMessenger;
+        private String mRootId;
+        private MediaSessionCompat.Token mMediaSessionToken;
+        private Bundle mExtras;
+
+        public MediaBrowserImplBase(Context context, ComponentName serviceComponent,
+                ConnectionCallback callback, Bundle rootHints) {
+            if (context == null) {
+                throw new IllegalArgumentException("context must not be null");
+            }
+            if (serviceComponent == null) {
+                throw new IllegalArgumentException("service component must not be null");
+            }
+            if (callback == null) {
+                throw new IllegalArgumentException("connection callback must not be null");
+            }
+            mContext = context;
+            mServiceComponent = serviceComponent;
+            mCallback = callback;
+            mRootHints = rootHints;
+        }
+
+        public void connect() {
+            if (mState != CONNECT_STATE_DISCONNECTED) {
+                throw new IllegalStateException("connect() called while not disconnected (state="
+                        + getStateLabel(mState) + ")");
+            }
+            // TODO: remove this extra check.
+            if (DBG) {
+                if (mServiceConnection != null) {
+                    throw new RuntimeException("mServiceConnection should be null. Instead it is "
+                            + mServiceConnection);
+                }
+            }
+            if (mServiceBinderWrapper != null) {
+                throw new RuntimeException("mServiceBinderWrapper should be null. Instead it is "
+                        + mServiceBinderWrapper);
+            }
+            if (mCallbacksMessenger != null) {
+                throw new RuntimeException("mCallbacksMessenger should be null. Instead it is "
+                        + mCallbacksMessenger);
+            }
+
+            mState = CONNECT_STATE_CONNECTING;
+
+            final Intent intent = new Intent(MediaBrowserServiceCompat.SERVICE_INTERFACE);
+            intent.setComponent(mServiceComponent);
+
+            final ServiceConnection thisConnection = mServiceConnection =
+                    new MediaServiceConnection();
+
+            boolean bound = false;
+            try {
+                bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+            } catch (Exception ex) {
+                Log.e(TAG, "Failed binding to service " + mServiceComponent);
+            }
+
+            if (!bound) {
+                // Tell them that it didn't work.  We are already on the main thread,
+                // but we don't want to do callbacks inside of connect().  So post it,
+                // and then check that we are on the same ServiceConnection.  We know
+                // we won't also get an onServiceConnected or onServiceDisconnected,
+                // so we won't be doing double callbacks.
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        // Ensure that nobody else came in or tried to connect again.
+                        if (thisConnection == mServiceConnection) {
+                            forceCloseConnection();
+                            mCallback.onConnectionFailed();
+                        }
+                    }
+                });
+            }
+
+            if (DBG) {
+                Log.d(TAG, "connect...");
+                dump();
+            }
+        }
+
+        public void disconnect() {
+            // It's ok to call this any state, because allowing this lets apps not have
+            // to check isConnected() unnecessarily.  They won't appreciate the extra
+            // assertions for this.  We do everything we can here to go back to a sane state.
+            if (mCallbacksMessenger != null) {
+                try {
+                    mServiceBinderWrapper.disconnect();
+                } catch (RemoteException ex) {
+                    // We are disconnecting anyway.  Log, just for posterity but it's not
+                    // a big problem.
+                    Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
+                }
+            }
+            forceCloseConnection();
+
+            if (DBG) {
+                Log.d(TAG, "disconnect...");
+                dump();
+            }
+        }
+
+        /**
+         * Null out the variables and unbind from the service.  This doesn't include
+         * calling disconnect on the service, because we only try to do that in the
+         * clean shutdown cases.
+         * <p>
+         * Everywhere that calls this EXCEPT for disconnect() should follow it with
+         * a call to mCallback.onConnectionFailed().  Disconnect doesn't do that callback
+         * for a clean shutdown, but everywhere else is a dirty shutdown and should
+         * notify the app.
+         */
+        private void forceCloseConnection() {
+            if (mServiceConnection != null) {
+                mContext.unbindService(mServiceConnection);
+            }
+            mState = CONNECT_STATE_DISCONNECTED;
+            mServiceConnection = null;
+            mServiceBinderWrapper = null;
+            mCallbacksMessenger = null;
+            mRootId = null;
+            mMediaSessionToken = null;
+        }
+
+        public boolean isConnected() {
+            return mState == CONNECT_STATE_CONNECTED;
+        }
+
+        public @NonNull
+        ComponentName getServiceComponent() {
+            if (!isConnected()) {
+                throw new IllegalStateException("getServiceComponent() called while not connected" +
+                        " (state=" + mState + ")");
+            }
+            return mServiceComponent;
+        }
+
+        public @NonNull String getRoot() {
+            if (!isConnected()) {
+                throw new IllegalStateException("getRoot() called while not connected"
+                        + "(state=" + getStateLabel(mState) + ")");
+            }
+            return mRootId;
+        }
+
+        public @Nullable
+        Bundle getExtras() {
+            if (!isConnected()) {
+                throw new IllegalStateException("getExtras() called while not connected (state="
+                        + getStateLabel(mState) + ")");
+            }
+            return mExtras;
+        }
+
+        public @NonNull MediaSessionCompat.Token getSessionToken() {
+            if (!isConnected()) {
+                throw new IllegalStateException("getSessionToken() called while not connected"
+                        + "(state=" + mState + ")");
+            }
+            return mMediaSessionToken;
+        }
+
+        public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+            // Check arguments.
+            if (parentId == null) {
+                throw new IllegalArgumentException("parentId is null");
+            }
+            if (callback == null) {
+                throw new IllegalArgumentException("callback is null");
+            }
+
+            // Update or create the subscription.
+            Subscription sub = mSubscriptions.get(parentId);
+            boolean newSubscription = sub == null;
+            if (newSubscription) {
+                sub = new Subscription(parentId);
+                mSubscriptions.put(parentId, sub);
+            }
+            sub.callback = callback;
+
+            // If we are connected, tell the service that we are watching.  If we aren't
+            // connected, the service will be told when we connect.
+            if (mState == CONNECT_STATE_CONNECTED) {
+                try {
+                    mServiceBinderWrapper.addSubscription(parentId);
+                } catch (RemoteException ex) {
+                    // Process is crashing.  We will disconnect, and upon reconnect we will
+                    // automatically reregister. So nothing to do here.
+                    Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
+                }
+            }
+        }
+
+        public void unsubscribe(@NonNull String parentId) {
+            // Check arguments.
+            if (TextUtils.isEmpty(parentId)) {
+                throw new IllegalArgumentException("parentId is empty.");
+            }
+
+            // Remove from our list.
+            final Subscription sub = mSubscriptions.remove(parentId);
+
+            // Tell the service if necessary.
+            if (mState == CONNECT_STATE_CONNECTED && sub != null) {
+                try {
+                    mServiceBinderWrapper.removeSubscription(parentId);
+                } catch (RemoteException ex) {
+                    // Process is crashing.  We will disconnect, and upon reconnect we will
+                    // automatically reregister. So nothing to do here.
+                    Log.d(TAG, "removeSubscription failed with RemoteException parentId="
+                            + parentId);
+                }
+            }
+        }
+
+        public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
+            if (TextUtils.isEmpty(mediaId)) {
+                throw new IllegalArgumentException("mediaId is empty.");
+            }
+            if (cb == null) {
+                throw new IllegalArgumentException("cb is null.");
+            }
+            if (mState != CONNECT_STATE_CONNECTED) {
+                Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        cb.onError(mediaId);
+                    }
+                });
+                return;
+            }
+            ResultReceiver receiver = new ResultReceiver(mHandler) {
+                @Override
+                protected void onReceiveResult(int resultCode, Bundle resultData) {
+                    if (resultCode != 0 || resultData == null
+                            || !resultData.containsKey(MediaBrowserServiceCompat.KEY_MEDIA_ITEM)) {
+                        cb.onError(mediaId);
+                        return;
+                    }
+                    Parcelable item =
+                            resultData.getParcelable(MediaBrowserServiceCompat.KEY_MEDIA_ITEM);
+                    if (!(item instanceof MediaItem)) {
+                        cb.onError(mediaId);
+                        return;
+                    }
+                    cb.onItemLoaded((MediaItem)item);
+                }
+            };
+            try {
+                mServiceBinderWrapper.getMediaItem(mediaId, receiver);
+            } catch (RemoteException e) {
+                Log.i(TAG, "Remote error getting media item.");
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        cb.onError(mediaId);
+                    }
+                });
+            }
+        }
+
+        /**
+         * For debugging.
+         */
+        private static String getStateLabel(int state) {
+            switch (state) {
+                case CONNECT_STATE_DISCONNECTED:
+                    return "CONNECT_STATE_DISCONNECTED";
+                case CONNECT_STATE_CONNECTING:
+                    return "CONNECT_STATE_CONNECTING";
+                case CONNECT_STATE_CONNECTED:
+                    return "CONNECT_STATE_CONNECTED";
+                case CONNECT_STATE_SUSPENDED:
+                    return "CONNECT_STATE_SUSPENDED";
+                default:
+                    return "UNKNOWN/" + state;
+            }
+        }
+
+        private final void onServiceConnected(final Messenger callback, final String root,
+                final MediaSessionCompat.Token session, final Bundle extra) {
+            // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
+            if (!isCurrent(callback, "onConnect")) {
+                return;
+            }
+            // Don't allow them to call us twice.
+            if (mState != CONNECT_STATE_CONNECTING) {
+                Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
+                        + "... ignoring");
+                return;
+            }
+            mRootId = root;
+            mMediaSessionToken = session;
+            mExtras = extra;
+            mState = CONNECT_STATE_CONNECTED;
+
+            if (DBG) {
+                Log.d(TAG, "ServiceCallbacks.onConnect...");
+                dump();
+            }
+            mCallback.onConnected();
+
+            // we may receive some subscriptions before we are connected, so re-subscribe
+            // everything now
+            for (String id : mSubscriptions.keySet()) {
+                try {
+                    mServiceBinderWrapper.addSubscription(id);
+                } catch (RemoteException ex) {
+                    // Process is crashing.  We will disconnect, and upon reconnect we will
+                    // automatically reregister. So nothing to do here.
+                    Log.d(TAG, "addSubscription failed with RemoteException parentId=" + id);
+                }
+            }
+        }
+
+        private final void onConnectionFailed(final Messenger callback) {
+            Log.e(TAG, "onConnectFailed for " + mServiceComponent);
+
+            // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
+            if (!isCurrent(callback, "onConnectFailed")) {
+                return;
+            }
+            // Don't allow them to call us twice.
+            if (mState != CONNECT_STATE_CONNECTING) {
+                Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
+                        + "... ignoring");
+                return;
+            }
+
+            // Clean up
+            forceCloseConnection();
+
+            // Tell the app.
+            mCallback.onConnectionFailed();
+        }
+
+        private final void onLoadChildren(final Messenger callback, final String parentId,
+                final List list) {
+            // Check that there hasn't been a disconnect or a different ServiceConnection.
+            if (!isCurrent(callback, "onLoadChildren")) {
+                return;
+            }
+
+            List<MediaItem> data = list;
+            if (DBG) {
+                Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
+            }
+
+            // Check that the subscription is still subscribed.
+            final Subscription subscription = mSubscriptions.get(parentId);
+            if (subscription == null) {
+                if (DBG) {
+                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
+                }
+                return;
+            }
+
+            // Tell the app.
+            subscription.callback.onChildrenLoaded(parentId, data);
+        }
+
+        /**
+         * Return true if {@code callback} is the current ServiceCallbacks.  Also logs if it's not.
+         */
+        private boolean isCurrent(Messenger callback, String funcName) {
+            if (mCallbacksMessenger != callback) {
+                if (mState != CONNECT_STATE_DISCONNECTED) {
+                    Log.i(TAG, funcName + " for " + mServiceComponent + " with mCallbacksMessenger="
+                            + mCallbacksMessenger + " this=" + this);
+                }
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Log internal state.
+         * @hide
+         */
+        void dump() {
+            Log.d(TAG, "MediaBrowserCompat...");
+            Log.d(TAG, "  mServiceComponent=" + mServiceComponent);
+            Log.d(TAG, "  mCallback=" + mCallback);
+            Log.d(TAG, "  mRootHints=" + mRootHints);
+            Log.d(TAG, "  mState=" + getStateLabel(mState));
+            Log.d(TAG, "  mServiceConnection=" + mServiceConnection);
+            Log.d(TAG, "  mServiceBinderWrapper=" + mServiceBinderWrapper);
+            Log.d(TAG, "  mCallbacksMessenger=" + mCallbacksMessenger);
+            Log.d(TAG, "  mRootId=" + mRootId);
+            Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
+        }
+
+        private class ServiceBinderWrapper {
+            private Messenger mMessenger;
+
+            public ServiceBinderWrapper(IBinder target) {
+                mMessenger = new Messenger(target);
+            }
+
+            void connect() throws RemoteException {
+                sendRequest(CLIENT_MSG_CONNECT, mContext.getPackageName(), mRootHints,
+                        mCallbacksMessenger);
+            }
+
+            void disconnect() throws RemoteException {
+                sendRequest(CLIENT_MSG_DISCONNECT, null, null, mCallbacksMessenger);
+            }
+
+            void addSubscription(String parentId) throws RemoteException {
+                sendRequest(CLIENT_MSG_ADD_SUBSCRIPTION, parentId, null, mCallbacksMessenger);
+            }
+
+            void removeSubscription(String parentId) throws RemoteException {
+                sendRequest(CLIENT_MSG_REMOVE_SUBSCRIPTION, parentId, null, mCallbacksMessenger);
+            }
+
+            void getMediaItem(String mediaId, ResultReceiver receiver) throws RemoteException {
+                Bundle data = new Bundle();
+                data.putParcelable(SERVICE_DATA_RESULT_RECEIVER, receiver);
+                sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, mediaId, data, null);
+            }
+
+            private void sendRequest(int what, Object obj, Bundle data, Messenger cbMessenger)
+                    throws RemoteException {
+                Message msg = Message.obtain();
+                msg.what = what;
+                msg.arg1 = CLIENT_VERSION_CURRENT;
+                msg.obj = obj;
+                msg.setData(data);
+                msg.replyTo = cbMessenger;
+                mMessenger.send(msg);
+            }
+        }
+
+        /**
+         * ServiceConnection to the other app.
+         */
+        private class MediaServiceConnection implements ServiceConnection {
+            @Override
+            public void onServiceConnected(final ComponentName name, final IBinder binder) {
+                postOrRun(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (DBG) {
+                            Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
+                                    + " binder=" + binder);
+                            dump();
+                        }
+
+                        // Make sure we are still the current connection, and that they haven't
+                        // called disconnect().
+                        if (!isCurrent("onServiceConnected")) {
+                            return;
+                        }
+
+                        // Save their binder
+                        mServiceBinderWrapper = new ServiceBinderWrapper(binder);
+
+                        // We make a new mServiceCallbacks each time we connect so that we can drop
+                        // responses from previous connections.
+                        mCallbacksMessenger = new Messenger(mHandler);
+
+                        mState = CONNECT_STATE_CONNECTING;
+
+                        // Call connect, which is async. When we get a response from that we will
+                        // say that we're connected.
+                        try {
+                            if (DBG) {
+                                Log.d(TAG, "ServiceCallbacks.onConnect...");
+                                dump();
+                            }
+                            mServiceBinderWrapper.connect();
+                        } catch (RemoteException ex) {
+                            // Connect failed, which isn't good. But the auto-reconnect on the
+                            // service will take over and we will come back.  We will also get the
+                            // onServiceDisconnected, which has all the cleanup code.  So let that
+                            // do it.
+                            Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
+                            if (DBG) {
+                                Log.d(TAG, "ServiceCallbacks.onConnect...");
+                                dump();
+                            }
+                        }
+                    }
+                });
+            }
+
+            @Override
+            public void onServiceDisconnected(final ComponentName name) {
+                postOrRun(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (DBG) {
+                            Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
+                                    + " this=" + this + " mServiceConnection=" +
+                                    mServiceConnection);
+                            dump();
+                        }
+
+                        // Make sure we are still the current connection, and that they haven't
+                        // called disconnect().
+                        if (!isCurrent("onServiceDisconnected")) {
+                            return;
+                        }
+
+                        // Clear out what we set in onServiceConnected
+                        mServiceBinderWrapper = null;
+                        mCallbacksMessenger = null;
+
+                        // And tell the app that it's suspended.
+                        mState = CONNECT_STATE_SUSPENDED;
+                        mCallback.onConnectionSuspended();
+                    }
+                });
+            }
+
+            private void postOrRun(Runnable r) {
+                if (Thread.currentThread() == mHandler.getLooper().getThread()) {
+                    r.run();
+                } else {
+                    mHandler.post(r);
+                }
+            }
+
+            /**
+             * Return true if this is the current ServiceConnection.  Also logs if it's not.
+             */
+            private boolean isCurrent(String funcName) {
+                if (mServiceConnection != this) {
+                    if (mState != CONNECT_STATE_DISCONNECTED) {
+                        // Check mState, because otherwise this log is noisy.
+                        Log.i(TAG, funcName + " for " + mServiceComponent +
+                                " with mServiceConnection=" + mServiceConnection + " this=" + this);
+                    }
+                    return false;
+                }
+                return true;
+            }
+        }
+
+        private class CallbackHandler extends Handler {
+            @Override
+            public void handleMessage(Message msg) {
+                Bundle data = msg.getData();
+                switch (msg.what) {
+                    case SERVICE_MSG_ON_CONNECT:
+                        onServiceConnected(mCallbacksMessenger, (String) msg.obj,
+                                (MediaSessionCompat.Token) data.getParcelable(
+                                        SERVICE_DATA_MEDIA_SESSION_TOKEN),
+                                data.getBundle(SERVICE_DATA_EXTRAS));
+                        break;
+                    case SERVICE_MSG_ON_CONNECT_FAILED:
+                        onConnectionFailed(mCallbacksMessenger);
+                        break;
+                    case SERVICE_MSG_ON_LOAD_CHILDREN:
+                        onLoadChildren(mCallbacksMessenger,  (String) msg.obj,
+                                data.getParcelableArrayList(SERVICE_DATA_MEDIA_ITEM_LIST));
+                        break;
+                    default:
+                        Log.w(TAG, "Unhandled message: " + msg
+                                + "\n  Client version: " + CLIENT_VERSION_CURRENT
+                                + "\n  Service version: " + msg.arg1);
+                }
+            }
+        }
+
+        private static class Subscription {
+            final String id;
+            SubscriptionCallback callback;
+
+            Subscription(String id) {
+                this.id = id;
+            }
+        }
+    }
+
+    static class MediaBrowserImplApi21 implements MediaBrowserImpl {
+        protected Object mBrowserObj;
+        protected Messenger mMessenger;
+        protected Handler mHandler = new Handler();
+
+        public MediaBrowserImplApi21(Context context, ComponentName serviceComponent,
+                ConnectionCallback callback, Bundle rootHints) {
+            mBrowserObj = MediaBrowserCompatApi21.createBrowser(context, serviceComponent,
+                    callback.mConnectionCallbackObj, rootHints);
+        }
+
+        @Override
+        public void connect() {
+            MediaBrowserCompatApi21.connect(mBrowserObj);
+        }
+
+        @Override
+        public void disconnect() {
+            MediaBrowserCompatApi21.disconnect(mBrowserObj);
+        }
+
+        @Override
+        public boolean isConnected() {
+            return MediaBrowserCompatApi21.isConnected(mBrowserObj);
+        }
+
+        @Override
+        public ComponentName getServiceComponent() {
+            return MediaBrowserCompatApi21.getServiceComponent(mBrowserObj);
+        }
+
+        @NonNull
+        @Override
+        public String getRoot() {
+            return MediaBrowserCompatApi21.getRoot(mBrowserObj);
+        }
+
+        @Nullable
+        @Override
+        public Bundle getExtras() {
+            return MediaBrowserCompatApi21.getExtras(mBrowserObj);
+        }
+
+        @NonNull
+        @Override
+        public MediaSessionCompat.Token getSessionToken() {
+            return MediaSessionCompat.Token.fromToken(
+                    MediaBrowserCompatApi21.getSessionToken(mBrowserObj));
+        }
+
+        @Override
+        public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+            MediaBrowserCompatApi21.subscribe(
+                    mBrowserObj, parentId, callback.mSubscriptionCallbackObj);
+        }
+
+        @Override
+        public void unsubscribe(@NonNull String parentId) {
+            MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
+        }
+
+        @Override
+        public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
+            if (TextUtils.isEmpty(mediaId)) {
+                throw new IllegalArgumentException("mediaId is empty.");
+            }
+            if (cb == null) {
+                throw new IllegalArgumentException("cb is null.");
+            }
+            if (!MediaBrowserCompatApi21.isConnected(mBrowserObj)) {
+                Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        cb.onError(mediaId);
+                    }
+                });
+                return;
+            }
+            if (mMessenger == null) {
+                Bundle extras = MediaBrowserCompatApi21.getExtras(mBrowserObj);
+                IBinder serviceBinder = BundleCompat.getBinder(extras, EXTRA_MESSENGER_BINDER);
+                if (serviceBinder != null) {
+                    mMessenger = new Messenger(serviceBinder);
+                }
+            }
+            if (mMessenger == null) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        // Default framework implementation.
+                        cb.onItemLoaded(null);
+                    }
+                });
+                return;
+            }
+            ResultReceiver receiver = new ResultReceiver(mHandler) {
+                @Override
+                protected void onReceiveResult(int resultCode, Bundle resultData) {
+                    if (resultCode != 0 || resultData == null
+                            || !resultData.containsKey(MediaBrowserServiceCompat.KEY_MEDIA_ITEM)) {
+                        cb.onError(mediaId);
+                        return;
+                    }
+                    Parcelable item =
+                            resultData.getParcelable(MediaBrowserServiceCompat.KEY_MEDIA_ITEM);
+                    if (!(item instanceof MediaItem)) {
+                        cb.onError(mediaId);
+                        return;
+                    }
+                    cb.onItemLoaded((MediaItem)item);
+                }
+            };
+            try {
+                Bundle data = new Bundle();
+                data.putParcelable(SERVICE_DATA_RESULT_RECEIVER, receiver);
+                sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, mediaId, data, null);
+            } catch (RemoteException e) {
+                Log.i(TAG, "Remote error getting media item.");
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        cb.onError(mediaId);
+                    }
+                });
+            }
+        }
+
+        private void sendRequest(int what, Object obj, Bundle data, Messenger cbMessenger)
+                throws RemoteException {
+            Message msg = Message.obtain();
+            msg.what = what;
+            msg.arg1 = CLIENT_VERSION_CURRENT;
+            msg.obj = obj;
+            msg.setData(data);
+            msg.replyTo = cbMessenger;
+            mMessenger.send(msg);
+        }
+    }
+
+    static class MediaBrowserImplApi23 extends MediaBrowserImplApi21 {
+        public MediaBrowserImplApi23(Context context, ComponentName serviceComponent,
+                ConnectionCallback callback, Bundle rootHints) {
+            super(context, serviceComponent, callback, rootHints);
+        }
+
+        @Override
+        public void getItem(@NonNull String mediaId, @NonNull ItemCallback cb) {
+            MediaBrowserCompatApi23.getItem(mBrowserObj, mediaId, cb.mItemCallbackObj);
+        }
+    }
+}
diff --git a/v4/java/android/support/v4/media/MediaBrowserProtocol.java b/v4/java/android/support/v4/media/MediaBrowserProtocol.java
new file mode 100644
index 0000000..7c8feb3
--- /dev/null
+++ b/v4/java/android/support/v4/media/MediaBrowserProtocol.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package android.support.v4.media;
+
+/***
+ * Defines the communication protocol for media browsers and media browser services.
+ * @hide
+ */
+class MediaBrowserProtocol {
+
+    /**
+     * MediaBrowserCompat will check the version of the connected MediaBrowserServiceCompat,
+     * and it will not send messages if they are introduced in the higher version of the
+     * MediaBrowserServiceCompat.
+     */
+    public static final int SERVICE_VERSION_1 = 1;
+    public static final int SERVICE_VERSION_CURRENT = SERVICE_VERSION_1;
+
+    /*
+     * Messages sent from the media browser service compat to the media browser compat.
+     * (Compat implementation for IMediaBrowserServiceCallbacks)
+     * DO NOT RENUMBER THESE!
+     */
+
+    /** (service v1)
+     * Sent after {@link MediaBrowserCompat#connect()} when the request has successfully
+     * completed.
+     * - arg1 : The service version
+     * - obj  : The root media item id
+     * - data
+     *     SERVICE_DATA_MEDIA_SESSION_TOKEN : Media session token
+     *     SERVICE_DATA_EXTRAS : An extras bundle which contains EXTRA_SERVICE_VERSION
+     */
+    public static final int SERVICE_MSG_ON_CONNECT = 1;
+
+    /** (service v1)
+     * Sent after {@link MediaBrowserCompat#connect()} when the connection to the media browser
+     * failed.
+     * - arg1 : service version
+     */
+    public static final int SERVICE_MSG_ON_CONNECT_FAILED = 2;
+
+    /** (service v1)
+     * Sent when the list of children is loaded or updated.
+     * - arg1 : The service version
+     * - obj  : The parent media item id
+     * - data
+     *     SERVICE_DATA_MEDIA_ITEM_LIST : An array list for the media item children
+     */
+    public static final int SERVICE_MSG_ON_LOAD_CHILDREN = 3;
+
+    public static final String SERVICE_DATA_MEDIA_SESSION_TOKEN = "data_media_session_token";
+    public static final String SERVICE_DATA_EXTRAS = "data_extras";
+    public static final String SERVICE_DATA_MEDIA_ITEM_LIST = "data_media_item_list";
+    public static final String SERVICE_DATA_RESULT_RECEIVER = "data_result_receiver";
+
+    public static final String EXTRA_SERVICE_VERSION = "extra_service_version";
+    public static final String EXTRA_MESSENGER_BINDER = "extra_messenger";
+
+    /**
+     * MediaBrowserServiceCompat will check the version of the MediaBrowserCompat, and it will not
+     * send messages if they are introduced in the higher version of the MediaBrowserCompat.
+     */
+    public static final int CLIENT_VERSION_1 = 1;
+    public static final int CLIENT_VERSION_CURRENT = CLIENT_VERSION_1;
+
+    /*
+     * Messages sent from the media browser compat to the media browser service compat.
+     * (Compat implementation for IMediaBrowserService)
+     * DO NOT RENUMBER THESE!
+     */
+
+    /** (client v1)
+     * Sent to connect to the media browse service compat.
+     * - arg1 : The client version
+     * - obj  : The package name
+     * - data : An optional root hints bundle of service-specific arguments
+     * - replayTo : Client messenger
+     */
+    public static final int CLIENT_MSG_CONNECT = 1;
+
+    /** (client v1)
+     * Sent to disconnect from the media browse service compat.
+     * - arg1 : The client version
+     * - replayTo : Client messenger
+     */
+    public static final int CLIENT_MSG_DISCONNECT = 2;
+
+    /** (client v1)
+     * Sent to subscribe for changes to the children of the specified media id.
+     * - arg1 : The client version
+     * - obj  : The media item id
+     * - replayTo : Client messenger
+     */
+    public static final int CLIENT_MSG_ADD_SUBSCRIPTION = 3;
+
+    /** (client v1)
+     * Sent to unsubscribe for changes to the children of the specified media id.
+     * - arg1 : The client version
+     * - obj  : The media item id
+     * - replayTo : Client messenger
+     */
+    public static final int CLIENT_MSG_REMOVE_SUBSCRIPTION = 4;
+
+    /** (client v1)
+     * Sent to retrieves a specific media item from the connected service.
+     * - arg1 : The client version
+     * - obj  : The media item id
+     * - data
+     *     SERVICE_DATA_RESULT_RECEIVER : Result receiver to get the result
+     */
+    public static final int CLIENT_MSG_GET_MEDIA_ITEM = 5;
+}
diff --git a/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java
new file mode 100644
index 0000000..205e789
--- /dev/null
+++ b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -0,0 +1,803 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.BundleCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.os.ResultReceiver;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import static android.support.v4.media.MediaBrowserProtocol.*;
+
+/**
+ * Base class for media browse services.
+ * <p>
+ * Media browse services enable applications to browse media content provided by an application
+ * and ask the application to start playing it.  They may also be used to control content that
+ * is already playing by way of a {@link MediaSessionCompat}.
+ * </p>
+ *
+ * To extend this class, you must declare the service in your manifest file with
+ * an intent filter with the {@link #SERVICE_INTERFACE} action.
+ *
+ * For example:
+ * </p><pre>
+ * &lt;service android:name=".MyMediaBrowserServiceCompat"
+ *          android:label="&#64;string/service_name" >
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.media.browse.MediaBrowserService" />
+ *     &lt;/intent-filter>
+ * &lt;/service>
+ * </pre>
+ */
+public abstract class MediaBrowserServiceCompat extends Service {
+    private static final String TAG = "MediaBrowserServiceCompat";
+    private static final boolean DBG = false;
+
+    private MediaBrowserServiceImpl mImpl;
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+
+    /**
+     * A key for passing the MediaItem to the ResultReceiver in getItem.
+     *
+     * @hide
+     */
+    public static final String KEY_MEDIA_ITEM = "media_item";
+
+    private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap();
+    private final ServiceHandler mHandler = new ServiceHandler();
+    MediaSessionCompat.Token mSession;
+
+    interface MediaBrowserServiceImpl {
+        void onCreate();
+        IBinder onBind(Intent intent);
+    }
+
+    class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl {
+        private Messenger mMessenger;
+
+        @Override
+        public void onCreate() {
+            mMessenger = new Messenger(mHandler);
+        }
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            if (SERVICE_INTERFACE.equals(intent.getAction())) {
+                return mMessenger.getBinder();
+            }
+            return null;
+        }
+    }
+
+    class MediaBrowserServiceImplApi21 implements MediaBrowserServiceImpl {
+        private Object mServiceObj;
+
+        @Override
+        public void onCreate() {
+            mServiceObj = MediaBrowserServiceCompatApi21.createService();
+            MediaBrowserServiceCompatApi21.onCreate(mServiceObj, new ServiceImplApi21());
+        }
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return MediaBrowserServiceCompatApi21.onBind(mServiceObj, intent);
+        }
+    }
+
+    class MediaBrowserServiceImplApi23 implements MediaBrowserServiceImpl {
+        private Object mServiceObj;
+
+        @Override
+        public void onCreate() {
+            mServiceObj = MediaBrowserServiceCompatApi23.createService();
+            MediaBrowserServiceCompatApi23.onCreate(mServiceObj, new ServiceImplApi23());
+        }
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return MediaBrowserServiceCompatApi23.onBind(mServiceObj, intent);
+        }
+    }
+
+    private final class ServiceHandler extends Handler {
+        private final ServiceImpl mServiceImpl = new ServiceImpl();
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case CLIENT_MSG_CONNECT:
+                    mServiceImpl.connect((String) msg.obj, msg.getData(),
+                            new ServiceCallbacksCompat(msg.replyTo));
+                    break;
+                case CLIENT_MSG_DISCONNECT:
+                    mServiceImpl.disconnect(new ServiceCallbacksCompat(msg.replyTo));
+                    break;
+                case CLIENT_MSG_ADD_SUBSCRIPTION:
+                    mServiceImpl.addSubscription((String) msg.obj,
+                            new ServiceCallbacksCompat(msg.replyTo));
+                    break;
+                case CLIENT_MSG_REMOVE_SUBSCRIPTION:
+                    mServiceImpl.removeSubscription((String) msg.obj,
+                            new ServiceCallbacksCompat(msg.replyTo));
+                    break;
+                case CLIENT_MSG_GET_MEDIA_ITEM:
+                    mServiceImpl.getMediaItem((String) msg.obj, (ResultReceiver) msg.getData()
+                            .getParcelable(SERVICE_DATA_RESULT_RECEIVER));
+                    break;
+                default:
+                    Log.w(TAG, "Unhandled message: " + msg
+                            + "\n  Service version: " + SERVICE_VERSION_CURRENT
+                            + "\n  Client version: " + msg.arg1);
+            }
+        }
+
+        public void postOrRun(Runnable r) {
+            if (Thread.currentThread() == getLooper().getThread()) {
+                r.run();
+            } else {
+                post(r);
+            }
+        }
+
+        public ServiceImpl getServiceImpl() {
+            return mServiceImpl;
+        }
+    }
+
+    /**
+     * All the info about a connection.
+     */
+    private class ConnectionRecord {
+        String pkg;
+        Bundle rootHints;
+        ServiceCallbacks callbacks;
+        BrowserRoot root;
+        HashSet<String> subscriptions = new HashSet();
+    }
+
+    /**
+     * Completion handler for asynchronous callback methods in {@link MediaBrowserServiceCompat}.
+     * <p>
+     * Each of the methods that takes one of these to send the result must call
+     * {@link #sendResult} to respond to the caller with the given results.  If those
+     * functions return without calling {@link #sendResult}, they must instead call
+     * {@link #detach} before returning, and then may call {@link #sendResult} when
+     * they are done.  If more than one of those methods is called, an exception will
+     * be thrown.
+     *
+     * @see MediaBrowserServiceCompat#onLoadChildren
+     * @see MediaBrowserServiceCompat#onLoadItem
+     */
+    public static class Result<T> {
+        private Object mDebug;
+        private boolean mDetachCalled;
+        private boolean mSendResultCalled;
+
+        Result(Object debug) {
+            mDebug = debug;
+        }
+
+        /**
+         * Send the result back to the caller.
+         */
+        public void sendResult(T result) {
+            if (mSendResultCalled) {
+                throw new IllegalStateException("sendResult() called twice for: " + mDebug);
+            }
+            mSendResultCalled = true;
+            onResultSent(result);
+        }
+
+        /**
+         * Detach this message from the current thread and allow the {@link #sendResult}
+         * call to happen later.
+         */
+        public void detach() {
+            if (mDetachCalled) {
+                throw new IllegalStateException("detach() called when detach() had already"
+                        + " been called for: " + mDebug);
+            }
+            if (mSendResultCalled) {
+                throw new IllegalStateException("detach() called when sendResult() had already"
+                        + " been called for: " + mDebug);
+            }
+            mDetachCalled = true;
+        }
+
+        boolean isDone() {
+            return mDetachCalled || mSendResultCalled;
+        }
+
+        /**
+         * Called when the result is sent, after assertions about not being called twice
+         * have happened.
+         */
+        void onResultSent(T result) {
+        }
+    }
+
+    private class ServiceImpl {
+        public void connect(final String pkg, final Bundle rootHints,
+                final ServiceCallbacks callbacks) {
+
+            final int uid = Binder.getCallingUid();
+            if (!isValidPackage(pkg, uid)) {
+                throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
+                        + " package=" + pkg);
+            }
+
+            mHandler.postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    final IBinder b = callbacks.asBinder();
+
+                    // Clear out the old subscriptions.  We are getting new ones.
+                    mConnections.remove(b);
+
+                    final ConnectionRecord connection = new ConnectionRecord();
+                    connection.pkg = pkg;
+                    connection.rootHints = rootHints;
+                    connection.callbacks = callbacks;
+
+                    connection.root =
+                            MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints);
+
+                    // If they didn't return something, don't allow this client.
+                    if (connection.root == null) {
+                        Log.i(TAG, "No root for client " + pkg + " from service "
+                                + getClass().getName());
+                        try {
+                            callbacks.onConnectFailed();
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. "
+                                    + "pkg=" + pkg);
+                        }
+                    } else {
+                        try {
+                            mConnections.put(b, connection);
+                            if (mSession != null) {
+                                callbacks.onConnect(connection.root.getRootId(),
+                                        mSession, connection.root.getExtras());
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "Calling onConnect() failed. Dropping client. "
+                                    + "pkg=" + pkg);
+                            mConnections.remove(b);
+                        }
+                    }
+                }
+            });
+        }
+
+        public void disconnect(final ServiceCallbacks callbacks) {
+            mHandler.postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    final IBinder b = callbacks.asBinder();
+
+                    // Clear out the old subscriptions.  We are getting new ones.
+                    final ConnectionRecord old = mConnections.remove(b);
+                    if (old != null) {
+                        // TODO
+                    }
+                }
+            });
+        }
+
+
+        public void addSubscription(final String id, final ServiceCallbacks callbacks) {
+            mHandler.postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    final IBinder b = callbacks.asBinder();
+
+                    // Get the record for the connection
+                    final ConnectionRecord connection = mConnections.get(b);
+                    if (connection == null) {
+                        Log.w(TAG, "addSubscription for callback that isn't registered id="
+                                + id);
+                        return;
+                    }
+
+                    MediaBrowserServiceCompat.this.addSubscription(id, connection);
+                }
+            });
+        }
+
+        public void removeSubscription(final String id, final ServiceCallbacks callbacks) {
+            mHandler.postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    final IBinder b = callbacks.asBinder();
+
+                    ConnectionRecord connection = mConnections.get(b);
+                    if (connection == null) {
+                        Log.w(TAG, "removeSubscription for callback that isn't registered id="
+                                + id);
+                        return;
+                    }
+                    if (!connection.subscriptions.remove(id)) {
+                        Log.w(TAG, "removeSubscription called for " + id
+                                + " which is not subscribed");
+                    }
+                }
+            });
+        }
+
+        public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
+            if (TextUtils.isEmpty(mediaId) || receiver == null) {
+                return;
+            }
+
+            mHandler.postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    performLoadItem(mediaId, receiver);
+                }
+            });
+        }
+    }
+
+    private class ServiceImplApi21 implements MediaBrowserServiceCompatApi21.ServiceImplApi21 {
+        final ServiceImpl mServiceImpl;
+
+        ServiceImplApi21() {
+            mServiceImpl = mHandler.getServiceImpl();
+        }
+
+        @Override
+        public void connect(final String pkg, final Bundle rootHints,
+                final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+            mServiceImpl.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks));
+        }
+
+        @Override
+        public void disconnect(final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+            mServiceImpl.disconnect(new ServiceCallbacksApi21(callbacks));
+        }
+
+
+        @Override
+        public void addSubscription(
+                final String id, final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+            mServiceImpl.addSubscription(id, new ServiceCallbacksApi21(callbacks));
+        }
+
+        @Override
+        public void removeSubscription(final String id,
+                final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+            mServiceImpl.removeSubscription(id, new ServiceCallbacksApi21(callbacks));
+        }
+    }
+
+    private class ServiceImplApi23 extends ServiceImplApi21
+            implements MediaBrowserServiceCompatApi23.ServiceImplApi23 {
+        @Override
+        public void getMediaItem(final String mediaId,
+                final MediaBrowserServiceCompatApi23.ItemCallback cb) {
+            ResultReceiver receiverCompat = new ResultReceiver(mHandler) {
+                @Override
+                protected void onReceiveResult(int resultCode, Bundle resultData) {
+                    MediaBrowserCompat.MediaItem item = resultData.getParcelable(KEY_MEDIA_ITEM);
+                    Parcel itemParcel = null;
+                    if (item != null) {
+                        itemParcel = Parcel.obtain();
+                        item.writeToParcel(itemParcel, 0);
+                    }
+                    cb.onItemLoaded(resultCode, resultData, itemParcel);
+                }
+            };
+            mServiceImpl.getMediaItem(mediaId, receiverCompat);
+        }
+    }
+
+    private interface ServiceCallbacks {
+        IBinder asBinder();
+        void onConnect(String root, MediaSessionCompat.Token session, Bundle extras)
+                throws RemoteException;
+        void onConnectFailed() throws RemoteException;
+        void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list)
+                throws RemoteException;
+    }
+
+    private class ServiceCallbacksCompat implements ServiceCallbacks {
+        final Messenger mCallbacks;
+
+        ServiceCallbacksCompat(Messenger callbacks) {
+            mCallbacks = callbacks;
+        }
+
+        public IBinder asBinder() {
+            return mCallbacks.getBinder();
+        }
+
+        public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras)
+                throws RemoteException {
+            if (extras == null) {
+                extras = new Bundle();
+            }
+            extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT);
+            Bundle data = new Bundle();
+            data.putParcelable(SERVICE_DATA_MEDIA_SESSION_TOKEN, session);
+            data.putBundle(SERVICE_DATA_EXTRAS, extras);
+            sendRequest(SERVICE_MSG_ON_CONNECT, root, data);
+        }
+
+        public void onConnectFailed() throws RemoteException {
+            sendRequest(SERVICE_MSG_ON_CONNECT_FAILED, null, null);
+        }
+
+        public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list)
+                throws RemoteException {
+            Bundle data = null;
+            if (list != null) {
+                data = new Bundle();
+                data.putParcelableArrayList(SERVICE_DATA_MEDIA_ITEM_LIST,
+                        list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list));
+            }
+            sendRequest(SERVICE_MSG_ON_LOAD_CHILDREN, mediaId, data);
+        }
+
+        private void sendRequest(int what, Object obj, Bundle data)
+                throws RemoteException {
+            Message msg = Message.obtain();
+            msg.what = what;
+            msg.arg1 = SERVICE_VERSION_CURRENT;
+            msg.obj = obj;
+            msg.setData(data);
+            mCallbacks.send(msg);
+        }
+    }
+
+    private class ServiceCallbacksApi21 implements ServiceCallbacks {
+        final MediaBrowserServiceCompatApi21.ServiceCallbacks mCallbacks;
+        Messenger mMessenger;
+
+        ServiceCallbacksApi21(MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+            mCallbacks = callbacks;
+        }
+
+        public IBinder asBinder() {
+            return mCallbacks.asBinder();
+        }
+
+        public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras)
+                throws RemoteException {
+            if (extras == null) {
+                extras = new Bundle();
+            }
+            mMessenger = new Messenger(mHandler);
+            BundleCompat.putBinder(extras, EXTRA_MESSENGER_BINDER, mMessenger.getBinder());
+            extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT);
+            mCallbacks.onConnect(root, session.getToken(), extras);
+        }
+
+        public void onConnectFailed() throws RemoteException {
+            mCallbacks.onConnectFailed();
+        }
+
+        public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list)
+                throws RemoteException {
+            List<Parcel> parcelList = null;
+            if (list != null) {
+                parcelList = new ArrayList<>();
+                for (MediaBrowserCompat.MediaItem item : list) {
+                    Parcel parcel = Parcel.obtain();
+                    item.writeToParcel(parcel, 0);
+                    parcelList.add(parcel);
+                }
+            }
+            mCallbacks.onLoadChildren(mediaId, parcelList);
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        if (Build.VERSION.SDK_INT >= 23) {
+            mImpl = new MediaBrowserServiceImplApi23();
+        } else if (Build.VERSION.SDK_INT >= 21) {
+            mImpl = new MediaBrowserServiceImplApi21();
+        } else {
+            mImpl = new MediaBrowserServiceImplBase();
+        }
+        mImpl.onCreate();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mImpl.onBind(intent);
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+    }
+
+    /**
+     * Called to get the root information for browsing by a particular client.
+     * <p>
+     * The implementation should verify that the client package has permission
+     * to access browse media information before returning the root id; it
+     * should return null if the client is not allowed to access this
+     * information.
+     * </p>
+     *
+     * @param clientPackageName The package name of the application which is
+     *            requesting access to browse media.
+     * @param clientUid The uid of the application which is requesting access to
+     *            browse media.
+     * @param rootHints An optional bundle of service-specific arguments to send
+     *            to the media browse service when connecting and retrieving the
+     *            root id for browsing, or null if none. The contents of this
+     *            bundle may affect the information returned when browsing.
+     * @return The {@link BrowserRoot} for accessing this app's content or null.
+     */
+    public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
+            int clientUid, @Nullable Bundle rootHints);
+
+    /**
+     * Called to get information about the children of a media item.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}
+     * with the list of children. If loading the children will be an expensive
+     * operation that should be performed on another thread,
+     * {@link Result#detach result.detach} may be called before returning from
+     * this function, and then {@link Result#sendResult result.sendResult}
+     * called when the loading is complete.
+     *
+     * @param parentId The id of the parent media item whose children are to be
+     *            queried.
+     * @param result The Result to send the list of children to, or null if the
+     *            id is invalid.
+     */
+    public abstract void onLoadChildren(@NonNull String parentId,
+            @NonNull Result<List<MediaBrowserCompat.MediaItem>> result);
+
+    /**
+     * Called to get information about a specific media item.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}. If
+     * loading the item will be an expensive operation {@link Result#detach
+     * result.detach} may be called before returning from this function, and
+     * then {@link Result#sendResult result.sendResult} called when the item has
+     * been loaded.
+     * <p>
+     * The default implementation sends a null result.
+     *
+     * @param itemId The id for the specific
+     *            {@link MediaBrowserCompat.MediaItem}.
+     * @param result The Result to send the item to, or null if the id is
+     *            invalid.
+     */
+    public void onLoadItem(String itemId, Result<MediaBrowserCompat.MediaItem> result) {
+        result.sendResult(null);
+    }
+
+    /**
+     * Call to set the media session.
+     * <p>
+     * This should be called as soon as possible during the service's startup.
+     * It may only be called once.
+     *
+     * @param token The token for the service's {@link MediaSessionCompat}.
+     */
+    public void setSessionToken(final MediaSessionCompat.Token token) {
+        if (token == null) {
+            throw new IllegalArgumentException("Session token may not be null.");
+        }
+        if (mSession != null) {
+            throw new IllegalStateException("The session token has already been set.");
+        }
+        mSession = token;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                for (IBinder key : mConnections.keySet()) {
+                    ConnectionRecord connection = mConnections.get(key);
+                    try {
+                        connection.callbacks.onConnect(connection.root.getRootId(), token,
+                                connection.root.getExtras());
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
+                        mConnections.remove(key);
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Gets the session token, or null if it has not yet been created
+     * or if it has been destroyed.
+     */
+    public @Nullable MediaSessionCompat.Token getSessionToken() {
+        return mSession;
+    }
+
+    /**
+     * Notifies all connected media browsers that the children of
+     * the specified parent id have changed in some way.
+     * This will cause browsers to fetch subscribed content again.
+     *
+     * @param parentId The id of the parent media item whose
+     * children changed.
+     */
+    public void notifyChildrenChanged(@NonNull final String parentId) {
+        if (parentId == null) {
+            throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                for (IBinder binder : mConnections.keySet()) {
+                    ConnectionRecord connection = mConnections.get(binder);
+                    if (connection.subscriptions.contains(parentId)) {
+                        performLoadChildren(parentId, connection);
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Return whether the given package is one of the ones that is owned by the uid.
+     */
+    private boolean isValidPackage(String pkg, int uid) {
+        if (pkg == null) {
+            return false;
+        }
+        final PackageManager pm = getPackageManager();
+        final String[] packages = pm.getPackagesForUid(uid);
+        final int N = packages.length;
+        for (int i=0; i<N; i++) {
+            if (packages[i].equals(pkg)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Save the subscription and if it is a new subscription send the results.
+     */
+    private void addSubscription(String id, ConnectionRecord connection) {
+        // Save the subscription
+        connection.subscriptions.add(id);
+
+        // send the results
+        performLoadChildren(id, connection);
+    }
+
+    /**
+     * Call onLoadChildren and then send the results back to the connection.
+     * <p>
+     * Callers must make sure that this connection is still connected.
+     */
+    private void performLoadChildren(final String parentId, final ConnectionRecord connection) {
+        final Result<List<MediaBrowserCompat.MediaItem>> result
+                = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) {
+            @Override
+            void onResultSent(List<MediaBrowserCompat.MediaItem> list) {
+                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
+                    if (DBG) {
+                        Log.d(TAG, "Not sending onLoadChildren result for connection that has"
+                                + " been disconnected. pkg=" + connection.pkg + " id=" + parentId);
+                    }
+                    return;
+                }
+
+                try {
+                    connection.callbacks.onLoadChildren(parentId, list);
+                } catch (RemoteException ex) {
+                    // The other side is in the process of crashing.
+                    Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
+                            + " package=" + connection.pkg);
+                }
+            }
+        };
+
+        onLoadChildren(parentId, result);
+
+        if (!result.isDone()) {
+            throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
+                    + " before returning for package=" + connection.pkg + " id=" + parentId);
+        }
+    }
+
+    private void performLoadItem(String itemId, final ResultReceiver receiver) {
+        final Result<MediaBrowserCompat.MediaItem> result =
+                new Result<MediaBrowserCompat.MediaItem>(itemId) {
+            @Override
+            void onResultSent(MediaBrowserCompat.MediaItem item) {
+                Bundle bundle = new Bundle();
+                bundle.putParcelable(KEY_MEDIA_ITEM, item);
+                receiver.send(0, bundle);
+            }
+        };
+
+        MediaBrowserServiceCompat.this.onLoadItem(itemId, result);
+
+        if (!result.isDone()) {
+            throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
+                    + " before returning for id=" + itemId);
+        }
+    }
+
+    /**
+     * Contains information that the browser service needs to send to the client
+     * when first connected.
+     */
+    public static final class BrowserRoot {
+        final private String mRootId;
+        final private Bundle mExtras;
+
+        /**
+         * Constructs a browser root.
+         * @param rootId The root id for browsing.
+         * @param extras Any extras about the browser service.
+         */
+        public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) {
+            if (rootId == null) {
+                throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " +
+                        "Use null for BrowserRoot instead.");
+            }
+            mRootId = rootId;
+            mExtras = extras;
+        }
+
+        /**
+         * Gets the root id for browsing.
+         */
+        public String getRootId() {
+            return mRootId;
+        }
+
+        /**
+         * Gets any extras about the brwoser service.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+    }
+}
diff --git a/v4/java/android/support/v4/media/MediaMetadataCompat.java b/v4/java/android/support/v4/media/MediaMetadataCompat.java
index 088b208..0d07826 100644
--- a/v4/java/android/support/v4/media/MediaMetadataCompat.java
+++ b/v4/java/android/support/v4/media/MediaMetadataCompat.java
@@ -78,7 +78,8 @@
     public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
 
     /**
-     * The date the media was created or published as TODO determine format.
+     * The date the media was created or published. The format is unspecified
+     * but RFC 3339 is recommended.
      */
     public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
 
@@ -360,7 +361,13 @@
     public RatingCompat getRating(@RatingKey String key) {
         RatingCompat rating = null;
         try {
-            rating = mBundle.getParcelable(key);
+            if (Build.VERSION.SDK_INT >= 21) {
+                // On platform version 21 or higher, mBundle stores a Rating object. Convert it to
+                // RatingCompat.
+                rating = RatingCompat.fromRating(mBundle.getParcelable(key));
+            } else {
+                rating = mBundle.getParcelable(key);
+            }
         } catch (Exception e) {
             // ignore, value was not a bitmap
             Log.w(TAG, "Failed to retrieve a key as Rating.", e);
@@ -509,31 +516,11 @@
             return null;
         }
 
-        Builder builder = new Builder();
-        for (String key : MediaMetadataCompatApi21.keySet(metadataObj)) {
-            Integer type = METADATA_KEYS_TYPE.get(key);
-            if (type != null) {
-                switch (type) {
-                    case METADATA_TYPE_BITMAP:
-                        builder.putBitmap(key,
-                                MediaMetadataCompatApi21.getBitmap(metadataObj, key));
-                        break;
-                    case METADATA_TYPE_LONG:
-                        builder.putLong(key,
-                                MediaMetadataCompatApi21.getLong(metadataObj, key));
-                        break;
-                    case METADATA_TYPE_RATING:
-                        builder.putRating(key, RatingCompat.fromRating(
-                                MediaMetadataCompatApi21.getRating(metadataObj, key)));
-                        break;
-                    case METADATA_TYPE_TEXT:
-                        builder.putText(key,
-                                MediaMetadataCompatApi21.getText(metadataObj, key));
-                        break;
-                }
-            }
-        }
-        MediaMetadataCompat metadata = builder.build();
+        Parcel p = Parcel.obtain();
+        MediaMetadataCompatApi21.writeToParcel(metadataObj, p, 0);
+        p.setDataPosition(0);
+        MediaMetadataCompat metadata = MediaMetadataCompat.CREATOR.createFromParcel(p);
+        p.recycle();
         metadata.mMetadataObj = metadataObj;
         return metadata;
     }
@@ -553,31 +540,11 @@
             return mMetadataObj;
         }
 
-        Object builderObj = MediaMetadataCompatApi21.Builder.newInstance();
-        for (String key : keySet()) {
-            Integer type = METADATA_KEYS_TYPE.get(key);
-            if (type != null) {
-                switch (type) {
-                    case METADATA_TYPE_BITMAP:
-                        MediaMetadataCompatApi21.Builder.putBitmap(builderObj, key,
-                                getBitmap(key));
-                        break;
-                    case METADATA_TYPE_LONG:
-                        MediaMetadataCompatApi21.Builder.putLong(builderObj, key,
-                                getLong(key));
-                        break;
-                    case METADATA_TYPE_RATING:
-                        MediaMetadataCompatApi21.Builder.putRating(builderObj, key,
-                                getRating(key).getRating());
-                        break;
-                    case METADATA_TYPE_TEXT:
-                        MediaMetadataCompatApi21.Builder.putText(builderObj, key,
-                                getText(key));
-                        break;
-                }
-            }
-        }
-        mMetadataObj = MediaMetadataCompatApi21.Builder.build(builderObj);
+        Parcel p = Parcel.obtain();
+        writeToParcel(p, 0);
+        p.setDataPosition(0);
+        mMetadataObj = MediaMetadataCompatApi21.createFromParcel(p);
+        p.recycle();
         return mMetadataObj;
     }
 
@@ -741,7 +708,13 @@
                             + " key cannot be used to put a Rating");
                 }
             }
-            mBundle.putParcelable(key, value);
+            if (Build.VERSION.SDK_INT >= 21) {
+                // On platform version 21 or higher, use Rating instead of RatingCompat so mBundle
+                // can be unmarshalled.
+                mBundle.putParcelable(key, (Parcelable) value.getRating());
+            } else {
+                mBundle.putParcelable(key, value);
+            }
             return this;
         }
 
diff --git a/v4/java/android/support/v4/media/session/MediaButtonReceiver.java b/v4/java/android/support/v4/media/session/MediaButtonReceiver.java
new file mode 100644
index 0000000..d5eb0e8
--- /dev/null
+++ b/v4/java/android/support/v4/media/session/MediaButtonReceiver.java
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media.session;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.view.KeyEvent;
+
+import java.util.List;
+
+/**
+ * A media button receiver receives and helps translate hardware media playback buttons,
+ * such as those found on wired and wireless headsets, into the appropriate callbacks
+ * in your app.
+ * <p />
+ * You can add this MediaButtonReceiver to your app by adding it directly to your
+ * AndroidManifest.xml:
+ * <pre>
+ * &lt;receiver android:name="android.support.v4.media.session.MediaButtonReceiver" &gt;
+ *   &lt;intent-filter&gt;
+ *     &lt;action android:name="android.intent.action.MEDIA_BUTTON" /&gt;
+ *   &lt;/intent-filter&gt;
+ * &lt;/receiver&gt;
+ * </pre>
+ * This class assumes you have a {@link Service} in your app that controls
+ * media playback via a {@link MediaSessionCompat}. That {@link Service} must
+ * include an intent filter that also handles {@link Intent#ACTION_MEDIA_BUTTON}:
+ * <pre>
+ * &lt;service android:name="com.example.android.MediaPlaybackService" &gt;
+ *   &lt;intent-filter&gt;
+ *     &lt;action android:name="android.intent.action.MEDIA_BUTTON" /&gt;
+ *   &lt;/intent-filter&gt;
+ * &lt;/service&gt;
+ * </pre>
+ *
+ * All {@link Intent}s sent to this MediaButtonReceiver will then be forwarded
+ * to the {@link Service}. Events can then be handled in
+ * {@link Service#onStartCommand(Intent, int, int)} by calling
+ * {@link MediaButtonReceiver#handleIntent(MediaSessionCompat, Intent)}, passing in
+ * your current {@link MediaSessionCompat}:
+ * <pre>
+ * private MediaSessionCompat mMediaSessionCompat = ...;
+ *
+ * public int onStartCommand(Intent intent, int flags, int startId) {
+ *   MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent);
+ *   return super.onStartCommand(intent, flags, startId);
+ * }
+ * </pre>
+ *
+ * This ensures that the correct callbacks to {@link MediaSessionCompat.Callback}
+ * will be triggered based on the incoming {@link KeyEvent}.
+ */
+public class MediaButtonReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Intent queryIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        queryIntent.setPackage(context.getPackageName());
+        PackageManager pm = context.getPackageManager();
+        List<ResolveInfo> resolveInfos = pm.queryIntentServices(queryIntent, 0);
+        if (resolveInfos.size() != 1) {
+            throw new IllegalStateException("Expected 1 Service that handles " +
+                    Intent.ACTION_MEDIA_BUTTON + ", found " + resolveInfos.size());
+        }
+        ResolveInfo resolveInfo = resolveInfos.get(0);
+        ComponentName componentName = new ComponentName(resolveInfo.serviceInfo.packageName,
+                resolveInfo.serviceInfo.name);
+        intent.setComponent(componentName);
+        context.startService(intent);
+    }
+
+    /**
+     * Extracts any available {@link KeyEvent} from an {@link Intent#ACTION_MEDIA_BUTTON}
+     * intent, passing it onto the {@link MediaSessionCompat} using
+     * {@link MediaControllerCompat#dispatchMediaButtonEvent(KeyEvent)}, which in turn
+     * will trigger callbacks to the {@link MediaSessionCompat.Callback} registered via
+     * {@link MediaSessionCompat#setCallback(MediaSessionCompat.Callback)}.
+     * <p />
+     * The returned {@link KeyEvent} is non-null if any {@link KeyEvent} is found and can
+     * be used if any additional processing is needed beyond what is done in the
+     * {@link MediaSessionCompat.Callback}. An example of is to prevent redelivery of a
+     * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE} Intent in the case of the Service being
+     * restarted (which, by default, will redeliver the last received Intent).
+     * <pre>
+     * KeyEvent keyEvent = MediaButtonReceiver.handleIntent(mediaSession, intent);
+     * if (keyEvent != null && keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
+     *   Intent emptyIntent = new Intent(intent);
+     *   emptyIntent.setAction("");
+     *   startService(emptyIntent);
+     * }
+     * </pre>
+     * @param mediaSessionCompat A {@link MediaSessionCompat} that has a
+     *            {@link MediaSessionCompat.Callback} set.
+     * @param intent The intent to parse.
+     * @return The extracted {@link KeyEvent} if found, or null.
+     */
+    public static KeyEvent handleIntent(MediaSessionCompat mediaSessionCompat, Intent intent) {
+        if (mediaSessionCompat == null || intent == null
+                || !Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
+                || !intent.hasExtra(Intent.EXTRA_KEY_EVENT)) {
+            return null;
+        }
+        KeyEvent ke = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+        MediaControllerCompat mediaController = mediaSessionCompat.getController();
+        mediaController.dispatchMediaButtonEvent(ke);
+        return ke;
+    }
+}
+
diff --git a/v4/java/android/support/v4/media/session/MediaControllerCompat.java b/v4/java/android/support/v4/media/session/MediaControllerCompat.java
index 1d2180c..a6a5c88 100644
--- a/v4/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/v4/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -92,7 +92,9 @@
         }
         mToken = sessionToken;
 
-        if (android.os.Build.VERSION.SDK_INT >= 21) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            mImpl = new MediaControllerImplApi23(context, sessionToken);
+        } else if (android.os.Build.VERSION.SDK_INT >= 21) {
             mImpl = new MediaControllerImplApi21(context, sessionToken);
         } else {
             mImpl = new MediaControllerImplBase(mToken);
@@ -555,7 +557,9 @@
             }
 
             public void post(int what, Object obj, Bundle data) {
-                obtainMessage(what, obj).sendToTarget();
+                Message msg = obtainMessage(what, obj);
+                msg.setData(data);
+                msg.sendToTarget();
             }
         }
     }
@@ -1328,6 +1332,14 @@
 
         @Override
         public void playFromUri(Uri uri, Bundle extras) {
+            if (uri == null || Uri.EMPTY.equals(uri)) {
+                throw new IllegalArgumentException(
+                        "You must specify a non-empty Uri for playFromUri.");
+            }
+            Bundle bundle = new Bundle();
+            bundle.putParcelable(MediaSessionCompat.ACTION_ARGUMENT_URI, uri);
+            bundle.putParcelable(MediaSessionCompat.ACTION_ARGUMENT_EXTRAS, extras);
+            sendCustomAction(MediaSessionCompat.ACTION_PLAY_FROM_URI, bundle);
         }
 
         @Override
diff --git a/v4/java/android/support/v4/media/session/MediaSessionCompat.java b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
index fa963df..d35ada6 100644
--- a/v4/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -19,9 +19,12 @@
 
 import android.app.Activity;
 import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Bundle;
@@ -77,6 +80,8 @@
  * backwards compatible fashion.
  */
 public class MediaSessionCompat {
+    private static final String TAG = "MediaSessionCompat";
+
     private final MediaSessionImpl mImpl;
     private final MediaControllerCompat mController;
     private final ArrayList<OnActiveChangeListener>
@@ -102,12 +107,51 @@
     public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
 
     /**
+     * Custom action to invoke playFromUri() for the forward compatibility.
+     *
+     * @hide
+     */
+    public static final String ACTION_PLAY_FROM_URI =
+            "android.support.v4.media.session.action.PLAY_FROM_URI";
+
+    /**
+     * Argument for use with {@link #ACTION_PLAY_FROM_URI} indicating URI to play.
+     *
+     * @hide
+     */
+    public static final String ACTION_ARGUMENT_URI =
+            "android.support.v4.media.session.action.ARGUMENT_URI";
+
+    /**
+     * Argument for use with {@link #ACTION_PLAY_FROM_URI} indicating extra bundle.
+     *
+     * @hide
+     */
+    public static final String ACTION_ARGUMENT_EXTRAS =
+            "android.support.v4.media.session.action.ARGUMENT_EXTRAS";
+
+    /**
+     * Creates a new session using a media button receiver from your manifest.
+     * Note that a media button receiver is required to support platform versions
+     * earlier than {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
+     *
+     * @param context The context.
+     * @param tag A short name for debugging purposes.
+     */
+    public MediaSessionCompat(Context context, String tag) {
+        this(context, tag, null, null);
+    }
+
+    /**
      * Creates a new session.
      *
      * @param context The context.
      * @param tag A short name for debugging purposes.
      * @param mediaButtonEventReceiver The component name for your receiver.
-     *            This must be non-null to support platform versions earlier
+     *            If null, this will attempt to find an appropriate
+     *            {@link BroadcastReceiver} that handles
+     *            {@link Intent#ACTION_MEDIA_BUTTON} from your manifest.
+     *            A receiver is required to support platform versions earlier
      *            than {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
      * @param mbrIntent The PendingIntent for your receiver component that
      *            handles media button events. This is optional and will be used
@@ -123,6 +167,24 @@
             throw new IllegalArgumentException("tag must not be null or empty");
         }
 
+        if (mediaButtonEventReceiver == null) {
+            Intent queryIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+            queryIntent.setPackage(context.getPackageName());
+            PackageManager pm = context.getPackageManager();
+            List<ResolveInfo> resolveInfos = pm.queryBroadcastReceivers(queryIntent, 0);
+            // If none are found, assume we are running on a newer platform version that does
+            // not require a media button receiver ComponentName. Later code will double check
+            // this assumption and throw an error if needed
+            if (resolveInfos.size() == 1) {
+                ResolveInfo resolveInfo = resolveInfos.get(0);
+                mediaButtonEventReceiver = new ComponentName(resolveInfo.activityInfo.packageName,
+                    resolveInfo.activityInfo.name);
+            } else if (resolveInfos.size() > 1) {
+                Log.w(TAG, "More than one BroadcastReceiver that handles " +
+                        Intent.ACTION_MEDIA_BUTTON + " was found, using null. Provide a " +
+                        "specific ComponentName to use as this session's media button receiver");
+            }
+        }
         if (mediaButtonEventReceiver != null && mbrIntent == null) {
             // construct a PendingIntent for the media button
             Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
@@ -250,8 +312,8 @@
      * <p>
      * On platforms earlier than
      * {@link android.os.Build.VERSION_CODES#LOLLIPOP},
-     * {@link #setMediaButtonReceiver(PendingIntent)} must be called before
-     * setting this to true.
+     * a media button event receiver should be set via the constructor to
+     * receive media button events.
      *
      * @param active Whether this session is active or not.
      */
@@ -675,7 +737,13 @@
 
             @Override
             public void onCustomAction(String action, Bundle extras) {
-                Callback.this.onCustomAction(action, extras);
+                if (action.equals(ACTION_PLAY_FROM_URI)) {
+                    Uri uri = (Uri) extras.getParcelable(ACTION_ARGUMENT_URI);
+                    Bundle bundle = (Bundle) extras.getParcelable(ACTION_ARGUMENT_EXTRAS);
+                    Callback.this.onPlayFromUri(uri, bundle);
+                } else {
+                    Callback.this.onCustomAction(action, extras);
+                }
             }
         }
 
@@ -1309,7 +1377,7 @@
                     if (!mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) != 0) {
                         if (android.os.Build.VERSION.SDK_INT >= 18) {
                             MediaSessionCompatApi18.registerMediaButtonEventReceiver(mContext,
-                                    mMediaButtonEventReceiver);
+                                    mMediaButtonEventReceiver, mComponentName);
                         } else {
                             MediaSessionCompatApi8.registerMediaButtonEventReceiver(mContext,
                                     mComponentName);
@@ -1318,7 +1386,7 @@
                     } else if (mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) == 0) {
                         if (android.os.Build.VERSION.SDK_INT >= 18) {
                             MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
-                                    mMediaButtonEventReceiver);
+                                    mMediaButtonEventReceiver, mComponentName);
                         } else {
                             MediaSessionCompatApi8.unregisterMediaButtonEventReceiver(mContext,
                                     mComponentName);
@@ -1348,7 +1416,7 @@
                 if (mIsMbrRegistered) {
                     if (android.os.Build.VERSION.SDK_INT >= 18) {
                         MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
-                                mMediaButtonEventReceiver);
+                                mMediaButtonEventReceiver, mComponentName);
                     } else {
                         MediaSessionCompatApi8.unregisterMediaButtonEventReceiver(mContext,
                                 mComponentName);
@@ -1373,7 +1441,7 @@
                     mVolumeProvider.onAdjustVolume(direction);
                 }
             } else {
-                mAudioManager.adjustStreamVolume(direction, mLocalStream, flags);
+                mAudioManager.adjustStreamVolume(mLocalStream, direction, flags);
             }
         }
 
@@ -1928,7 +1996,8 @@
 
         @Override
         public void setCallback(Callback callback, Handler handler) {
-            MediaSessionCompatApi21.setCallback(mSessionObj, callback.mCallbackObj, handler);
+            MediaSessionCompatApi21.setCallback(mSessionObj,
+                    callback == null ? null : callback.mCallbackObj, handler);
         }
 
         @Override
@@ -1974,12 +2043,14 @@
 
         @Override
         public void setPlaybackState(PlaybackStateCompat state) {
-            MediaSessionCompatApi21.setPlaybackState(mSessionObj, state.getPlaybackState());
+            MediaSessionCompatApi21.setPlaybackState(mSessionObj,
+                    state == null ? null : state.getPlaybackState());
         }
 
         @Override
         public void setMetadata(MediaMetadataCompat metadata) {
-            MediaSessionCompatApi21.setMetadata(mSessionObj, metadata.getMediaMetadata());
+            MediaSessionCompatApi21.setMetadata(mSessionObj,
+                    metadata == null ? null : metadata.getMediaMetadata());
         }
 
         @Override
diff --git a/v4/java/android/support/v4/os/IResultReceiver.aidl b/v4/java/android/support/v4/os/IResultReceiver.aidl
new file mode 100644
index 0000000..cd23ff3
--- /dev/null
+++ b/v4/java/android/support/v4/os/IResultReceiver.aidl
@@ -0,0 +1,24 @@
+/*
+** Copyright 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.
+*/
+
+package android.support.v4.os;
+
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IResultReceiver {
+    void send(int resultCode, in Bundle resultData);
+}
diff --git a/v4/java/android/support/v4/os/ResultReceiver.aidl b/v4/java/android/support/v4/os/ResultReceiver.aidl
new file mode 100644
index 0000000..81c81f6
--- /dev/null
+++ b/v4/java/android/support/v4/os/ResultReceiver.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 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.
+*/
+
+package android.support.v4.os;
+
+parcelable ResultReceiver;
diff --git a/v4/java/android/support/v4/os/ResultReceiver.java b/v4/java/android/support/v4/os/ResultReceiver.java
new file mode 100644
index 0000000..f0dc001
--- /dev/null
+++ b/v4/java/android/support/v4/os/ResultReceiver.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.os;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.support.v4.os.IResultReceiver;
+
+/**
+ * Generic interface for receiving a callback result from someone.  Use this
+ * by creating a subclass and implement {@link #onReceiveResult}, which you can
+ * then pass to others and send through IPC, and receive results they
+ * supply with {@link #send}.
+ *
+ * <p>Note: the implementation underneath is just a simple wrapper around
+ * a {@link Binder} that is used to perform the communication.  This means
+ * semantically you should treat it as such: this class does not impact process
+ * lifecycle management (you must be using some higher-level component to tell
+ * the system that your process needs to continue running), the connection will
+ * break if your process goes away for any reason, etc.</p>
+ * @hide
+ */
+public class ResultReceiver implements Parcelable {
+    final boolean mLocal;
+    final Handler mHandler;
+    
+    IResultReceiver mReceiver;
+    
+    class MyRunnable implements Runnable {
+        final int mResultCode;
+        final Bundle mResultData;
+        
+        MyRunnable(int resultCode, Bundle resultData) {
+            mResultCode = resultCode;
+            mResultData = resultData;
+        }
+        
+        public void run() {
+            onReceiveResult(mResultCode, mResultData);
+        }
+    }
+    
+    class MyResultReceiver extends IResultReceiver.Stub {
+        public void send(int resultCode, Bundle resultData) {
+            if (mHandler != null) {
+                mHandler.post(new MyRunnable(resultCode, resultData));
+            } else {
+                onReceiveResult(resultCode, resultData);
+            }
+        }
+    }
+    
+    /**
+     * Create a new ResultReceive to receive results.  Your
+     * {@link #onReceiveResult} method will be called from the thread running
+     * <var>handler</var> if given, or from an arbitrary thread if null.
+     */
+    public ResultReceiver(Handler handler) {
+        mLocal = true;
+        mHandler = handler;
+    }
+    
+    /**
+     * Deliver a result to this receiver.  Will call {@link #onReceiveResult},
+     * always asynchronously if the receiver has supplied a Handler in which
+     * to dispatch the result.
+     * @param resultCode Arbitrary result code to deliver, as defined by you.
+     * @param resultData Any additional data provided by you.
+     */
+    public void send(int resultCode, Bundle resultData) {
+        if (mLocal) {
+            if (mHandler != null) {
+                mHandler.post(new MyRunnable(resultCode, resultData));
+            } else {
+                onReceiveResult(resultCode, resultData);
+            }
+            return;
+        }
+        
+        if (mReceiver != null) {
+            try {
+                mReceiver.send(resultCode, resultData);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+    
+    /**
+     * Override to receive results delivered to this object.
+     * 
+     * @param resultCode Arbitrary result code delivered by the sender, as
+     * defined by the sender.
+     * @param resultData Any additional data provided by the sender.
+     */
+    protected void onReceiveResult(int resultCode, Bundle resultData) {
+    }
+    
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        synchronized (this) {
+            if (mReceiver == null) {
+                mReceiver = new MyResultReceiver();
+            }
+            out.writeStrongBinder(mReceiver.asBinder());
+        }
+    }
+
+    ResultReceiver(Parcel in) {
+        mLocal = false;
+        mHandler = null;
+        mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder());
+    }
+    
+    public static final Parcelable.Creator<ResultReceiver> CREATOR
+            = new Parcelable.Creator<ResultReceiver>() {
+        public ResultReceiver createFromParcel(Parcel in) {
+            return new ResultReceiver(in);
+        }
+        public ResultReceiver[] newArray(int size) {
+            return new ResultReceiver[size];
+        }
+    };
+}
diff --git a/v4/java/android/support/v4/view/ActionProvider.java b/v4/java/android/support/v4/view/ActionProvider.java
index d195a3a..070ea46 100644
--- a/v4/java/android/support/v4/view/ActionProvider.java
+++ b/v4/java/android/support/v4/view/ActionProvider.java
@@ -60,6 +60,63 @@
  * </code></pre>
  * </li></ul></p>
  *
+ * <h3>Creating a custom action provider</h3>
+ *
+ * <p>To create a custom action provider, extend ActionProvider and implement
+ * its callback methods as necessary. In particular, implement the following
+ * methods:</p>
+ *
+ * <dl>
+ * <dt>{@link #ActionProvider ActionProvider()} constructor</dt>
+ * <dd>This constructor is passed the application context. You should
+ * save the context in a member field to use in the other callback methods.</dd>
+ *
+ * <dt>{@link #onCreateActionView onCreateActionView(MenuItem)}</dt>
+ * <dd>The system calls this method when the action provider is created.
+ * You define the action provider's layout through the implementation of this
+ * method. Use the context acquired
+ * from the constructor to instantiate a {@link android.view.LayoutInflater} and
+ * inflate your action provider's layout from an XML resource, then hook up
+ * event listeners for the view's components. For example:
+ *
+ *<pre>
+ * public View onCreateActionView(MenuItem forItem) {
+ *     // Inflate the action provider to be shown on the action bar.
+ *     LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ *     View providerView =
+ *         layoutInflater.inflate(R.layout.my_action_provider, null);
+ *     ImageButton button =
+ *         (ImageButton) providerView.findViewById(R.id.button);
+ *     button.setOnClickListener(new View.OnClickListener() {
+ *         &#64;Override
+ *         public void onClick(View v) {
+ *             // Do something...
+ *         }
+ *     });
+ *     return providerView;
+ * }</pre>
+ * </dd>
+ *
+ * <dt>{@link #onPerformDefaultAction onPerformDefaultAction()}</dt>
+ * <dd><p>The system calls this method when the user selects a menu item from the action
+ * overflow. The action provider should perform a default action for the
+ * menu item. The system does not call this method if the menu item opens a submenu.</p>
+ *
+ * <p>If your action provider presents a submenu through the
+ * {@link #onPrepareSubMenu onPrepareSubMenu()} callback, the submenu
+ * appears even if the action provider is in the overflow menu.
+ * Thus, the system never calls {@link #onPerformDefaultAction
+ * onPerformDefaultAction()} if there is a submenu.</p>
+ *
+ * <p class="note"> <strong>Note:</strong> An activity or a fragment that
+ * implements <code>onOptionsItemSelected()</code> can override the action
+ * provider's default behavior (unless it uses a submenu) by handling the
+ * item-selected event and returning <code>true</code>. In this case, the
+ * system does not call
+ * {@link #onPerformDefaultAction onPerformDefaultAction()}.</p></dd>
+ * </dl>
+ *
+ *
  * @see android.support.v4.view.MenuItemCompat#setActionProvider(android.view.MenuItem, ActionProvider)
  * @see android.support.v4.view.MenuItemCompat#getActionProvider(android.view.MenuItem)
  */
diff --git a/v4/java/android/support/v4/view/PagerAdapter.java b/v4/java/android/support/v4/view/PagerAdapter.java
index ef52404..55fb9c1 100644
--- a/v4/java/android/support/v4/view/PagerAdapter.java
+++ b/v4/java/android/support/v4/view/PagerAdapter.java
@@ -76,7 +76,8 @@
  * the method {@link #getItemPosition(Object)}.</p>
  */
 public abstract class PagerAdapter {
-    private DataSetObservable mObservable = new DataSetObservable();
+    private final DataSetObservable mObservable = new DataSetObservable();
+    private DataSetObserver mViewPagerObserver;
 
     public static final int POSITION_UNCHANGED = -1;
     public static final int POSITION_NONE = -2;
@@ -273,6 +274,11 @@
      * and associated views should update.
      */
     public void notifyDataSetChanged() {
+        synchronized (this) {
+            if (mViewPagerObserver != null) {
+                mViewPagerObserver.onChanged();
+            }
+        }
         mObservable.notifyChanged();
     }
 
@@ -294,6 +300,12 @@
         mObservable.unregisterObserver(observer);
     }
 
+    void setViewPagerObserver(DataSetObserver observer) {
+        synchronized (this) {
+            mViewPagerObserver = observer;
+        }
+    }
+
     /**
      * This method may be called by the ViewPager to obtain a title string
      * to describe the specified page. This method may return null
diff --git a/v4/java/android/support/v4/view/PagerTitleStrip.java b/v4/java/android/support/v4/view/PagerTitleStrip.java
index 72a83e6..6edbed8 100644
--- a/v4/java/android/support/v4/view/PagerTitleStrip.java
+++ b/v4/java/android/support/v4/view/PagerTitleStrip.java
@@ -423,35 +423,37 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
         if (widthMode != MeasureSpec.EXACTLY) {
             throw new IllegalStateException("Must measure with an exact width");
         }
 
-        int childHeight = heightSize;
-        int minHeight = getMinHeight();
-        int padding = 0;
-        padding = getPaddingTop() + getPaddingBottom();
-        childHeight -= padding;
+        final int heightPadding = getPaddingTop() + getPaddingBottom();
+        final int childHeightSpec = getChildMeasureSpec(heightMeasureSpec,
+                heightPadding, LayoutParams.WRAP_CONTENT);
 
-        final int maxWidth = Math.max(0, (int) (widthSize * 0.8f));
-        final int childWidthSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
-        final int maxHeight = Math.min(0, childHeight);
-        final int childHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
+        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        final int widthPadding = (int) (widthSize * 0.2f);
+        final int childWidthSpec = getChildMeasureSpec(widthMeasureSpec,
+                widthPadding, LayoutParams.WRAP_CONTENT);
 
         mPrevText.measure(childWidthSpec, childHeightSpec);
         mCurrText.measure(childWidthSpec, childHeightSpec);
         mNextText.measure(childWidthSpec, childHeightSpec);
 
+        final int height;
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         if (heightMode == MeasureSpec.EXACTLY) {
-            setMeasuredDimension(widthSize, heightSize);
+            height = MeasureSpec.getSize(heightMeasureSpec);
         } else {
-            int textHeight = mCurrText.getMeasuredHeight();
-            setMeasuredDimension(widthSize, Math.max(minHeight, textHeight + padding));
+            final int textHeight = mCurrText.getMeasuredHeight();
+            final int minHeight = getMinHeight();
+            height = Math.max(minHeight, textHeight + heightPadding);
         }
+
+        final int childState = ViewCompat.getMeasuredState(mCurrText);
+        final int measuredHeight = ViewCompat.resolveSizeAndState(height, heightMeasureSpec,
+                childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);
+        setMeasuredDimension(widthSize, measuredHeight);
     }
 
     @Override
diff --git a/v4/java/android/support/v4/view/ViewCompat.java b/v4/java/android/support/v4/view/ViewCompat.java
index d3dce89..b88d7e5 100644
--- a/v4/java/android/support/v4/view/ViewCompat.java
+++ b/v4/java/android/support/v4/view/ViewCompat.java
@@ -27,6 +27,7 @@
 import android.support.annotation.FloatRange;
 import android.support.annotation.IdRes;
 import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
@@ -276,6 +277,73 @@
      */
     public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true,
+            value = {
+                    SCROLL_INDICATOR_TOP,
+                    SCROLL_INDICATOR_BOTTOM,
+                    SCROLL_INDICATOR_LEFT,
+                    SCROLL_INDICATOR_RIGHT,
+                    SCROLL_INDICATOR_START,
+                    SCROLL_INDICATOR_END,
+            })
+    public @interface ScrollIndicators {}
+
+    /**
+     * Scroll indicator direction for the top edge of the view.
+     *
+     * @see #setScrollIndicators(int)
+     * @see #setScrollIndicators(int, int)
+     * @see #getScrollIndicators()
+     */
+    public static final int SCROLL_INDICATOR_TOP = 0x1;
+
+    /**
+     * Scroll indicator direction for the bottom edge of the view.
+     *
+     * @see #setScrollIndicators(int)
+     * @see #setScrollIndicators(int, int)
+     * @see #getScrollIndicators()
+     */
+    public static final int SCROLL_INDICATOR_BOTTOM = 0x2;
+
+    /**
+     * Scroll indicator direction for the left edge of the view.
+     *
+     * @see #setScrollIndicators(int)
+     * @see #setScrollIndicators(int, int)
+     * @see #getScrollIndicators()
+     */
+    public static final int SCROLL_INDICATOR_LEFT = 0x4;
+
+    /**
+     * Scroll indicator direction for the right edge of the view.
+     *
+     * @see #setScrollIndicators(int)
+     * @see #setScrollIndicators(int, int)
+     * @see #getScrollIndicators()
+     */
+    public static final int SCROLL_INDICATOR_RIGHT = 0x8;
+
+    /**
+     * Scroll indicator direction for the starting edge of the view.
+     *
+     * @see #setScrollIndicators(View, int)
+     * @see #setScrollIndicators(View, int, int)
+     * @see #getScrollIndicators(View)
+     */
+    public static final int SCROLL_INDICATOR_START = 0x10;
+
+    /**
+     * Scroll indicator direction for the ending edge of the view.
+     *
+     * @see #setScrollIndicators(int)
+     * @see #setScrollIndicators(int, int)
+     * @see #getScrollIndicators()
+     */
+    public static final int SCROLL_INDICATOR_END = 0x20;
+
     interface ViewCompatImpl {
         public boolean canScrollHorizontally(View v, int direction);
         public boolean canScrollVertically(View v, int direction);
@@ -384,6 +452,10 @@
         int combineMeasuredStates(int curState, int newState);
         public float getZ(View view);
         public boolean isAttachedToWindow(View view);
+        public boolean hasOnClickListeners(View view);
+        public void setScrollIndicators(View view, int indicators);
+        public void setScrollIndicators(View view, int indicators, int mask);
+        public int getScrollIndicators(View view);
     }
 
     static class BaseViewCompatImpl implements ViewCompatImpl {
@@ -963,6 +1035,26 @@
         public boolean isAttachedToWindow(View view) {
             return ViewCompatBase.isAttachedToWindow(view);
         }
+
+        @Override
+        public boolean hasOnClickListeners(View view) {
+            return false;
+        }
+
+        @Override
+        public int getScrollIndicators(View view) {
+            return 0;
+        }
+
+        @Override
+        public void setScrollIndicators(View view, int indicators) {
+            // no-op
+        }
+
+        @Override
+        public void setScrollIndicators(View view, int indicators, int mask) {
+            // no-op
+        }
     }
 
     static class EclairMr1ViewCompatImpl extends BaseViewCompatImpl {
@@ -1222,7 +1314,14 @@
         }
     }
 
-    static class JBViewCompatImpl extends ICSViewCompatImpl {
+    static class ICSMr1ViewCompatImpl extends ICSViewCompatImpl {
+        @Override
+        public boolean hasOnClickListeners(View view) {
+            return ViewCompatICSMr1.hasOnClickListeners(view);
+        }
+    }
+
+    static class JBViewCompatImpl extends ICSMr1ViewCompatImpl {
         @Override
         public boolean hasTransientState(View view) {
             return ViewCompatJB.hasTransientState(view);
@@ -1529,10 +1628,29 @@
         }
     }
 
+    static class MarshmallowViewCompatImpl extends LollipopViewCompatImpl {
+        @Override
+        public void setScrollIndicators(View view, int indicators) {
+            ViewCompatMarshmallow.setScrollIndicators(view, indicators);
+        }
+
+        @Override
+        public void setScrollIndicators(View view, int indicators, int mask) {
+            ViewCompatMarshmallow.setScrollIndicators(view, indicators, mask);
+        }
+
+        @Override
+        public int getScrollIndicators(View view) {
+            return ViewCompatMarshmallow.getScrollIndicators(view);
+        }
+    }
+
     static final ViewCompatImpl IMPL;
     static {
         final int version = android.os.Build.VERSION.SDK_INT;
-        if (version >= 21) {
+        if (version >= 23) {
+            IMPL = new MarshmallowViewCompatImpl();
+        } else if (version >= 21) {
             IMPL = new LollipopViewCompatImpl();
         } else if (version >= 19) {
             IMPL = new KitKatViewCompatImpl();
@@ -1540,6 +1658,8 @@
             IMPL = new JbMr1ViewCompatImpl();
         } else if (version >= 16) {
             IMPL = new JBViewCompatImpl();
+        } else if (version >= 15) {
+            IMPL = new ICSMr1ViewCompatImpl();
         } else if (version >= 14) {
             IMPL = new ICSViewCompatImpl();
         } else if (version >= 11) {
@@ -2513,7 +2633,7 @@
      * @param value The y location of the pivot point.
      */
     public static void setPivotY(View view, float value) {
-        IMPL.setPivotX(view, value);
+        IMPL.setPivotY(view, value);
     }
 
     public static float getRotation(View view) {
@@ -3085,4 +3205,76 @@
     public static boolean isAttachedToWindow(View view) {
         return IMPL.isAttachedToWindow(view);
     }
+
+    /**
+     * Returns whether the provided view has an attached {@link View.OnClickListener}.
+     *
+     * @return true if there is a listener, false if there is none.
+     */
+    public static boolean hasOnClickListeners(View view) {
+        return IMPL.hasOnClickListeners(view);
+    }
+
+    /**
+     * Sets the state of all scroll indicators.
+     * <p>
+     * See {@link #setScrollIndicators(View, int, int)} for usage information.
+     *
+     * @param indicators a bitmask of indicators that should be enabled, or
+     *                   {@code 0} to disable all indicators
+     *
+     * @see #setScrollIndicators(View, int, int)
+     * @see #getScrollIndicators(View)
+     */
+    public static void setScrollIndicators(@NonNull View view, @ScrollIndicators int indicators) {
+        IMPL.setScrollIndicators(view, indicators);
+    }
+
+    /**
+     * Sets the state of the scroll indicators specified by the mask. To change
+     * all scroll indicators at once, see {@link #setScrollIndicators(View, int)}.
+     * <p>
+     * When a scroll indicator is enabled, it will be displayed if the view
+     * can scroll in the direction of the indicator.
+     * <p>
+     * Multiple indicator types may be enabled or disabled by passing the
+     * logical OR of the desired types. If multiple types are specified, they
+     * will all be set to the same enabled state.
+     * <p>
+     * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators}
+     *
+     * @param indicators the indicator direction, or the logical OR of multiple
+     *             indicator directions. One or more of:
+     *             <ul>
+     *               <li>{@link #SCROLL_INDICATOR_TOP}</li>
+     *               <li>{@link #SCROLL_INDICATOR_BOTTOM}</li>
+     *               <li>{@link #SCROLL_INDICATOR_LEFT}</li>
+     *               <li>{@link #SCROLL_INDICATOR_RIGHT}</li>
+     *               <li>{@link #SCROLL_INDICATOR_START}</li>
+     *               <li>{@link #SCROLL_INDICATOR_END}</li>
+     *             </ul>
+     *
+     * @see #setScrollIndicators(View, int)
+     * @see #getScrollIndicators(View)
+     */
+    public static void setScrollIndicators(@NonNull View view, @ScrollIndicators int indicators,
+            @ScrollIndicators int mask) {
+        IMPL.setScrollIndicators(view, indicators, mask);
+    }
+
+    /**
+     * Returns a bitmask representing the enabled scroll indicators.
+     * <p>
+     * For example, if the top and left scroll indicators are enabled and all
+     * other indicators are disabled, the return value will be
+     * {@code ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_LEFT}.
+     * <p>
+     * To check whether the bottom scroll indicator is enabled, use the value
+     * of {@code (ViewCompat.getScrollIndicators(view) & ViewCompat.SCROLL_INDICATOR_BOTTOM) != 0}.
+     *
+     * @return a bitmask representing the enabled scroll indicators
+     */
+    public static int getScrollIndicators(@NonNull View view) {
+        return IMPL.getScrollIndicators(view);
+    }
 }
diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java
index f19104a..c6f3648 100644
--- a/v4/java/android/support/v4/view/ViewPager.java
+++ b/v4/java/android/support/v4/view/ViewPager.java
@@ -144,7 +144,10 @@
     private int mRestoredCurItem = -1;
     private Parcelable mRestoredAdapterState = null;
     private ClassLoader mRestoredClassLoader = null;
+
     private Scroller mScroller;
+    private boolean mIsScrollStarted;
+
     private PagerObserver mObserver;
 
     private int mPageMargin;
@@ -388,6 +391,10 @@
     @Override
     protected void onDetachedFromWindow() {
         removeCallbacks(mEndScrollRunnable);
+        // To be on the safe side, abort the scroller
+        if ((mScroller != null) && !mScroller.isFinished()) {
+            mScroller.abortAnimation();
+        }
         super.onDetachedFromWindow();
     }
 
@@ -411,7 +418,7 @@
      */
     public void setAdapter(PagerAdapter adapter) {
         if (mAdapter != null) {
-            mAdapter.unregisterDataSetObserver(mObserver);
+            mAdapter.setViewPagerObserver(null);
             mAdapter.startUpdate(this);
             for (int i = 0; i < mItems.size(); i++) {
                 final ItemInfo ii = mItems.get(i);
@@ -432,7 +439,7 @@
             if (mObserver == null) {
                 mObserver = new PagerObserver();
             }
-            mAdapter.registerDataSetObserver(mObserver);
+            mAdapter.setViewPagerObserver(mObserver);
             mPopulatePending = false;
             final boolean wasFirstLayout = mFirstLayout;
             mFirstLayout = true;
@@ -829,7 +836,21 @@
             setScrollingCacheEnabled(false);
             return;
         }
-        int sx = getScrollX();
+
+        int sx;
+        boolean wasScrolling = (mScroller != null) && !mScroller.isFinished();
+        if (wasScrolling) {
+            // We're in the middle of a previously initiated scrolling. Check to see
+            // whether that scrolling has actually started (if we always call getStartX
+            // we can get a stale value from the scroller if it hadn't yet had its first
+            // computeScrollOffset call) to decide what is the current scrolling position.
+            sx = mIsScrollStarted ? mScroller.getCurrX() : mScroller.getStartX();
+            // And abort the current scrolling.
+            mScroller.abortAnimation();
+            setScrollingCacheEnabled(false);
+        } else {
+            sx = getScrollX();
+        }
         int sy = getScrollY();
         int dx = x - sx;
         int dy = y - sy;
@@ -849,7 +870,7 @@
         final float distance = halfWidth + halfWidth *
                 distanceInfluenceForSnapDuration(distanceRatio);
 
-        int duration = 0;
+        int duration;
         velocity = Math.abs(velocity);
         if (velocity > 0) {
             duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
@@ -860,6 +881,9 @@
         }
         duration = Math.min(duration, MAX_SETTLE_DURATION);
 
+        // Reset the "scroll started" flag. It will be flipped to true in all places
+        // where we call computeScrollOffset().
+        mIsScrollStarted = false;
         mScroller.startScroll(sx, sy, dx, dy, duration);
         ViewCompat.postInvalidateOnAnimation(this);
     }
@@ -1642,6 +1666,7 @@
 
     @Override
     public void computeScroll() {
+        mIsScrollStarted = true;
         if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
             int oldX = getScrollX();
             int oldY = getScrollY();
@@ -1822,15 +1847,18 @@
         if (needPopulate) {
             // Done with scroll, no longer want to cache view drawing.
             setScrollingCacheEnabled(false);
-            mScroller.abortAnimation();
-            int oldX = getScrollX();
-            int oldY = getScrollY();
-            int x = mScroller.getCurrX();
-            int y = mScroller.getCurrY();
-            if (oldX != x || oldY != y) {
-                scrollTo(x, y);
-                if (x != oldX) {
-                    pageScrolled(x);
+            boolean wasScrolling = !mScroller.isFinished();
+            if (wasScrolling) {
+                mScroller.abortAnimation();
+                int oldX = getScrollX();
+                int oldY = getScrollY();
+                int x = mScroller.getCurrX();
+                int y = mScroller.getCurrY();
+                if (oldX != x || oldY != y) {
+                    scrollTo(x, y);
+                    if (x != oldX) {
+                        pageScrolled(x);
+                    }
                 }
             }
         }
@@ -1878,13 +1906,7 @@
         if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
             // Release the drag.
             if (DEBUG) Log.v(TAG, "Intercept done!");
-            mIsBeingDragged = false;
-            mIsUnableToDrag = false;
-            mActivePointerId = INVALID_POINTER;
-            if (mVelocityTracker != null) {
-                mVelocityTracker.recycle();
-                mVelocityTracker = null;
-            }
+            resetTouch();
             return false;
         }
 
@@ -1970,6 +1992,7 @@
                 mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
                 mIsUnableToDrag = false;
 
+                mIsScrollStarted = true;
                 mScroller.computeScrollOffset();
                 if (mScrollState == SCROLL_STATE_SETTLING &&
                         Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
@@ -2051,6 +2074,11 @@
             case MotionEvent.ACTION_MOVE:
                 if (!mIsBeingDragged) {
                     final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+                    if (pointerIndex == -1) {
+                        // A child has consumed some touch events and put us into an inconsistent state.
+                        needsInvalidate = resetTouch();
+                        break;
+                    }
                     final float x = MotionEventCompat.getX(ev, pointerIndex);
                     final float xDiff = Math.abs(x - mLastMotionX);
                     final float y = MotionEventCompat.getY(ev, pointerIndex);
@@ -2102,17 +2130,13 @@
                             totalDelta);
                     setCurrentItemInternal(nextPage, true, true, initialVelocity);
 
-                    mActivePointerId = INVALID_POINTER;
-                    endDrag();
-                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+                    needsInvalidate = resetTouch();
                 }
                 break;
             case MotionEvent.ACTION_CANCEL:
                 if (mIsBeingDragged) {
                     scrollToItem(mCurItem, true, 0, false);
-                    mActivePointerId = INVALID_POINTER;
-                    endDrag();
-                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+                    needsInvalidate = resetTouch();
                 }
                 break;
             case MotionEventCompat.ACTION_POINTER_DOWN: {
@@ -2134,6 +2158,14 @@
         return true;
     }
 
+    private boolean resetTouch() {
+        boolean needsInvalidate;
+        mActivePointerId = INVALID_POINTER;
+        endDrag();
+        needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+        return needsInvalidate;
+    }
+
     private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
         final ViewParent parent = getParent();
         if (parent != null) {
diff --git a/v4/java/android/support/v4/widget/DrawerLayout.java b/v4/java/android/support/v4/widget/DrawerLayout.java
index a9560ad..549b8ea 100644
--- a/v4/java/android/support/v4/widget/DrawerLayout.java
+++ b/v4/java/android/support/v4/widget/DrawerLayout.java
@@ -59,17 +59,20 @@
 
 /**
  * DrawerLayout acts as a top-level container for window content that allows for
- * interactive "drawer" views to be pulled out from the edge of the window.
+ * interactive "drawer" views to be pulled out from one or both vertical edges of the window.
  *
  * <p>Drawer positioning and layout is controlled using the <code>android:layout_gravity</code>
  * attribute on child views corresponding to which side of the view you want the drawer
- * to emerge from: left or right. (Or start/end on platform versions that support layout direction.)
+ * to emerge from: left or right (or start/end on platform versions that support layout direction.)
+ * Note that you can only have one drawer view for each vertical edge of the window. If your
+ * layout configures more than one drawer view per vertical edge of the window, an exception will
+ * be thrown at runtime.
  * </p>
  *
  * <p>To use a DrawerLayout, position your primary content view as the first child with
- * a width and height of <code>match_parent</code>. Add drawers as child views after the main
- * content view and set the <code>layout_gravity</code> appropriately. Drawers commonly use
- * <code>match_parent</code> for height with a fixed width.</p>
+ * width and height of <code>match_parent</code> and no <code>layout_gravity></code>.
+ * Add drawers as child views after the main content view and set the <code>layout_gravity</code>
+ * appropriately. Drawers commonly use <code>match_parent</code> for height with a fixed width.</p>
  *
  * <p>{@link DrawerListener} can be used to monitor the state and motion of drawer views.
  * Avoid performing expensive operations such as layout during animation as it can cause
@@ -110,7 +113,8 @@
     public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
 
     /** @hide */
-    @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN})
+    @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN,
+            LOCK_MODE_UNDEFINED})
     @Retention(RetentionPolicy.SOURCE)
     private @interface LockMode {}
 
@@ -131,6 +135,11 @@
      */
     public static final int LOCK_MODE_LOCKED_OPEN = 2;
 
+    /**
+     * The drawer's lock state is reset to default.
+     */
+    public static final int LOCK_MODE_UNDEFINED = 3;
+
     /** @hide */
     @IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
     @Retention(RetentionPolicy.SOURCE)
@@ -189,8 +198,12 @@
     private int mDrawerState;
     private boolean mInLayout;
     private boolean mFirstLayout = true;
-    private int mLockModeLeft;
-    private int mLockModeRight;
+
+    private @LockMode int mLockModeLeft = LOCK_MODE_UNDEFINED;
+    private @LockMode int mLockModeRight = LOCK_MODE_UNDEFINED;
+    private @LockMode int mLockModeStart = LOCK_MODE_UNDEFINED;
+    private @LockMode int mLockModeEnd = LOCK_MODE_UNDEFINED;
+
     private boolean mDisallowInterceptRequested;
     private boolean mChildrenCanceledTouch;
 
@@ -544,11 +557,22 @@
     public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) {
         final int absGravity = GravityCompat.getAbsoluteGravity(edgeGravity,
                 ViewCompat.getLayoutDirection(this));
-        if (absGravity == Gravity.LEFT) {
-            mLockModeLeft = lockMode;
-        } else if (absGravity == Gravity.RIGHT) {
-            mLockModeRight = lockMode;
+
+        switch (edgeGravity) {
+            case Gravity.LEFT:
+                mLockModeLeft = lockMode;
+                break;
+            case Gravity.RIGHT:
+                mLockModeRight = lockMode;
+                break;
+            case GravityCompat.START:
+                mLockModeStart = lockMode;
+                break;
+            case GravityCompat.END:
+                mLockModeEnd = lockMode;
+                break;
         }
+
         if (lockMode != LOCK_MODE_UNLOCKED) {
             // Cancel interaction in progress
             final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger;
@@ -566,8 +590,8 @@
                 if (toClose != null) {
                     closeDrawer(toClose);
                 }
-                break;
-            // default: do nothing
+            break;
+                // default: do nothing
         }
     }
 
@@ -607,13 +631,51 @@
      */
     @LockMode
     public int getDrawerLockMode(@EdgeGravity int edgeGravity) {
-        final int absGravity = GravityCompat.getAbsoluteGravity(
-                edgeGravity, ViewCompat.getLayoutDirection(this));
-        if (absGravity == Gravity.LEFT) {
-            return mLockModeLeft;
-        } else if (absGravity == Gravity.RIGHT) {
-            return mLockModeRight;
+        int layoutDirection = ViewCompat.getLayoutDirection(this);
+
+        switch (edgeGravity) {
+            case Gravity.LEFT:
+                if (mLockModeLeft != LOCK_MODE_UNDEFINED) {
+                    return mLockModeLeft;
+                }
+                int leftLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+                        mLockModeStart : mLockModeEnd;
+                if (leftLockMode != LOCK_MODE_UNDEFINED) {
+                    return leftLockMode;
+                }
+                break;
+            case Gravity.RIGHT:
+                if (mLockModeRight != LOCK_MODE_UNDEFINED) {
+                    return mLockModeRight;
+                }
+                int rightLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+                        mLockModeEnd : mLockModeStart;
+                if (rightLockMode != LOCK_MODE_UNDEFINED) {
+                    return rightLockMode;
+                }
+                break;
+            case GravityCompat.START:
+                if (mLockModeStart != LOCK_MODE_UNDEFINED) {
+                    return mLockModeStart;
+                }
+                int startLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+                        mLockModeLeft : mLockModeRight;
+                if (startLockMode != LOCK_MODE_UNDEFINED) {
+                    return startLockMode;
+                }
+                break;
+            case GravityCompat.END:
+                if (mLockModeEnd != LOCK_MODE_UNDEFINED) {
+                    return mLockModeEnd;
+                }
+                int endLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+                        mLockModeRight : mLockModeLeft;
+                if (endLockMode != LOCK_MODE_UNDEFINED) {
+                    return endLockMode;
+                }
+                break;
         }
+
         return LOCK_MODE_UNLOCKED;
     }
 
@@ -626,13 +688,8 @@
      */
     @LockMode
     public int getDrawerLockMode(View drawerView) {
-        final int absGravity = getDrawerViewAbsoluteGravity(drawerView);
-        if (absGravity == Gravity.LEFT) {
-            return mLockModeLeft;
-        } else if (absGravity == Gravity.RIGHT) {
-            return mLockModeRight;
-        }
-        return LOCK_MODE_UNLOCKED;
+        final int drawerGravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
+        return getDrawerLockMode(drawerGravity);
     }
 
     /**
@@ -712,8 +769,8 @@
 
     void dispatchOnDrawerClosed(View drawerView) {
         final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
-        if (lp.knownOpen) {
-            lp.knownOpen = false;
+        if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
+            lp.openState = 0;
             if (mListener != null) {
                 mListener.onDrawerClosed(drawerView);
             }
@@ -734,8 +791,8 @@
 
     void dispatchOnDrawerOpened(View drawerView) {
         final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
-        if (!lp.knownOpen) {
-            lp.knownOpen = true;
+        if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 0) {
+            lp.openState = LayoutParams.FLAG_IS_OPENED;
             if (mListener != null) {
                 mListener.onDrawerOpened(drawerView);
             }
@@ -806,7 +863,8 @@
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             final View child = getChildAt(i);
-            if (((LayoutParams) child.getLayoutParams()).knownOpen) {
+            final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
+            if ((childLp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
                 return child;
             }
         }
@@ -951,6 +1009,7 @@
                             gravityToString(childGravity) + " but this " + TAG + " already has a " +
                             "drawer view along that edge");
                 }
+                foundDrawers = foundDrawers | childGravity;
                 final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
                         mMinDrawerMargin + lp.leftMargin + lp.rightMargin,
                         lp.width);
@@ -1435,13 +1494,15 @@
             throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
         }
 
+        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
         if (mFirstLayout) {
-            final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
             lp.onScreen = 1.f;
-            lp.knownOpen = true;
+            lp.openState = LayoutParams.FLAG_IS_OPENED;
 
             updateChildrenImportantForAccessibility(drawerView, true);
         } else {
+            lp.openState |= LayoutParams.FLAG_IS_OPENING;
+
             if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
                 mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
             } else {
@@ -1477,11 +1538,13 @@
             throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
         }
 
+        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
         if (mFirstLayout) {
-            final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
             lp.onScreen = 0.f;
-            lp.knownOpen = false;
+            lp.openState = 0;
         } else {
+            lp.openState |= LayoutParams.FLAG_IS_CLOSING;
+
             if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
                 mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(),
                         drawerView.getTop());
@@ -1521,7 +1584,8 @@
         if (!isDrawerView(drawer)) {
             throw new IllegalArgumentException("View " + drawer + " is not a drawer");
         }
-        return ((LayoutParams) drawer.getLayoutParams()).knownOpen;
+        LayoutParams drawerLp = (LayoutParams) drawer.getLayoutParams();
+        return (drawerLp.openState & LayoutParams.FLAG_IS_OPENED) == 1;
     }
 
     /**
@@ -1705,8 +1769,18 @@
             }
         }
 
-        setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
-        setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
+        if (ss.lockModeLeft != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
+        }
+        if (ss.lockModeRight != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
+        }
+        if (ss.lockModeStart != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeStart, GravityCompat.START);
+        }
+        if (ss.lockModeEnd != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeEnd, GravityCompat.END);
+        }
     }
 
     @Override
@@ -1714,13 +1788,26 @@
         final Parcelable superState = super.onSaveInstanceState();
         final SavedState ss = new SavedState(superState);
 
-        final View openDrawer = findOpenDrawer();
-        if (openDrawer != null) {
-            ss.openDrawerGravity = ((LayoutParams) openDrawer.getLayoutParams()).gravity;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            // Is the current child fully opened (that is, not closing)?
+            boolean isOpenedAndNotClosing = (lp.openState == LayoutParams.FLAG_IS_OPENED);
+            // Is the current child opening?
+            boolean isClosedAndOpening = (lp.openState == LayoutParams.FLAG_IS_OPENING);
+            if (isOpenedAndNotClosing || isClosedAndOpening) {
+                // If one of the conditions above holds, save the child's gravity
+                // so that we open that child during state restore.
+                ss.openDrawerGravity = lp.gravity;
+                break;
+            }
         }
 
         ss.lockModeLeft = mLockModeLeft;
         ss.lockModeRight = mLockModeRight;
+        ss.lockModeStart = mLockModeStart;
+        ss.lockModeEnd = mLockModeEnd;
 
         return ss;
     }
@@ -1766,12 +1853,18 @@
      */
     protected static class SavedState extends BaseSavedState {
         int openDrawerGravity = Gravity.NO_GRAVITY;
-        int lockModeLeft = LOCK_MODE_UNLOCKED;
-        int lockModeRight = LOCK_MODE_UNLOCKED;
+        @LockMode int lockModeLeft;
+        @LockMode int lockModeRight;
+        @LockMode int lockModeStart;
+        @LockMode int lockModeEnd;
 
         public SavedState(Parcel in) {
             super(in);
             openDrawerGravity = in.readInt();
+            lockModeLeft = in.readInt();
+            lockModeRight = in.readInt();
+            lockModeStart = in.readInt();
+            lockModeEnd = in.readInt();
         }
 
         public SavedState(Parcelable superState) {
@@ -1782,6 +1875,10 @@
         public void writeToParcel(Parcel dest, int flags) {
             super.writeToParcel(dest, flags);
             dest.writeInt(openDrawerGravity);
+            dest.writeInt(lockModeLeft);
+            dest.writeInt(lockModeRight);
+            dest.writeInt(lockModeStart);
+            dest.writeInt(lockModeEnd);
         }
 
         public static final Parcelable.Creator<SavedState> CREATOR =
@@ -1965,11 +2062,14 @@
     }
 
     public static class LayoutParams extends ViewGroup.MarginLayoutParams {
+        private static final int FLAG_IS_OPENED = 0x1;
+        private static final int FLAG_IS_OPENING = 0x2;
+        private static final int FLAG_IS_CLOSING = 0x4;
 
         public int gravity = Gravity.NO_GRAVITY;
-        float onScreen;
-        boolean isPeeking;
-        boolean knownOpen;
+        private float onScreen;
+        private boolean isPeeking;
+        private int openState;
 
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
diff --git a/v4/java/android/support/v4/widget/NestedScrollView.java b/v4/java/android/support/v4/widget/NestedScrollView.java
index 788761a..27e4307 100644
--- a/v4/java/android/support/v4/widget/NestedScrollView.java
+++ b/v4/java/android/support/v4/widget/NestedScrollView.java
@@ -31,6 +31,7 @@
 import android.support.v4.view.NestedScrollingChildHelper;
 import android.support.v4.view.NestedScrollingParent;
 import android.support.v4.view.NestedScrollingParentHelper;
+import android.support.v4.view.ScrollingView;
 import android.support.v4.view.VelocityTrackerCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -61,13 +62,35 @@
  * Nested scrolling is enabled by default.
  */
 public class NestedScrollView extends FrameLayout implements NestedScrollingParent,
-        NestedScrollingChild {
+        NestedScrollingChild, ScrollingView {
     static final int ANIMATED_SCROLL_GAP = 250;
 
     static final float MAX_SCROLL_FACTOR = 0.5f;
 
     private static final String TAG = "NestedScrollView";
 
+    /**
+     * Interface definition for a callback to be invoked when the scroll
+     * X or Y positions of a view change.
+     *
+     * <p>This version of the interface works on all versions of Android, back to API v4.</p>
+     *
+     * @see #setOnScrollChangeListener(OnScrollChangeListener)
+     */
+    public interface OnScrollChangeListener {
+        /**
+         * Called when the scroll position of a view changes.
+         *
+         * @param v The view whose scroll position has changed.
+         * @param scrollX Current horizontal scroll origin.
+         * @param scrollY Current vertical scroll origin.
+         * @param oldScrollX Previous horizontal scroll origin.
+         * @param oldScrollY Previous vertical scroll origin.
+         */
+        void onScrollChange(NestedScrollView v, int scrollX, int scrollY,
+                int oldScrollX, int oldScrollY);
+    }
+
     private long mLastScroll;
 
     private final Rect mTempRect = new Rect();
@@ -153,6 +176,8 @@
 
     private float mVerticalScrollFactor;
 
+    private OnScrollChangeListener mOnScrollChangeListener;
+
     public NestedScrollView(Context context) {
         this(context, null);
     }
@@ -245,6 +270,7 @@
 
     @Override
     public void onStopNestedScroll(View target) {
+        mParentHelper.onStopNestedScroll(target);
         stopNestedScroll();
     }
 
@@ -376,6 +402,19 @@
     }
 
     /**
+     * Register a callback to be invoked when the scroll X or Y positions of
+     * this view change.
+     * <p>This version of the method works on all versions of Android, back to API v4.</p>
+     *
+     * @param l The listener to notify when the scroll X or Y position changes.
+     * @see android.view.View#getScrollX()
+     * @see android.view.View#getScrollY()
+     */
+    public void setOnScrollChangeListener(OnScrollChangeListener l) {
+        mOnScrollChangeListener = l;
+    }
+
+    /**
      * @return Returns true this ScrollView can be scrolled
      */
     private boolean canScroll() {
@@ -430,6 +469,15 @@
     }
 
     @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+        super.onScrollChanged(l, t, oldl, oldt);
+
+        if (mOnScrollChangeListener != null) {
+            mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
+        }
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
@@ -576,13 +624,6 @@
             return true;
         }
 
-        /*
-         * Don't try to intercept touch if we can't scroll anyway.
-         */
-        if (getScrollY() == 0 && !ViewCompat.canScrollVertically(this, 1)) {
-            return false;
-        }
-
         switch (action & MotionEventCompat.ACTION_MASK) {
             case MotionEvent.ACTION_MOVE: {
                 /*
@@ -657,6 +698,9 @@
                 mIsBeingDragged = false;
                 mActivePointerId = INVALID_POINTER;
                 recycleVelocityTracker();
+                if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0, getScrollRange())) {
+                    ViewCompat.postInvalidateOnAnimation(this);
+                }
                 stopNestedScroll();
                 break;
             case MotionEventCompat.ACTION_POINTER_UP:
@@ -795,17 +839,23 @@
 
                     if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                         flingWithNestedDispatch(-initialVelocity);
+                    } else if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
+                            getScrollRange())) {
+                        ViewCompat.postInvalidateOnAnimation(this);
                     }
-
-                    mActivePointerId = INVALID_POINTER;
-                    endDrag();
                 }
+                mActivePointerId = INVALID_POINTER;
+                endDrag();
                 break;
             case MotionEvent.ACTION_CANCEL:
                 if (mIsBeingDragged && getChildCount() > 0) {
-                    mActivePointerId = INVALID_POINTER;
-                    endDrag();
+                    if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
+                            getScrollRange())) {
+                        ViewCompat.postInvalidateOnAnimation(this);
+                    }
                 }
+                mActivePointerId = INVALID_POINTER;
+                endDrag();
                 break;
             case MotionEventCompat.ACTION_POINTER_DOWN: {
                 final int index = MotionEventCompat.getActionIndex(ev);
@@ -942,6 +992,10 @@
             clampedY = true;
         }
 
+        if (clampedY) {
+            mScroller.springBack(newScrollX, newScrollY, 0, 0, 0, getScrollRange());
+        }
+
         onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
 
         return clampedX || clampedY;
@@ -1280,9 +1334,10 @@
     /**
      * <p>The scroll range of a scroll view is the overall height of all of its
      * children.</p>
+     * @hide
      */
     @Override
-    protected int computeVerticalScrollRange() {
+    public int computeVerticalScrollRange() {
         final int count = getChildCount();
         final int contentHeight = getHeight() - getPaddingBottom() - getPaddingTop();
         if (count == 0) {
@@ -1301,11 +1356,36 @@
         return scrollRange;
     }
 
+    /** @hide */
     @Override
-    protected int computeVerticalScrollOffset() {
+    public int computeVerticalScrollOffset() {
         return Math.max(0, super.computeVerticalScrollOffset());
     }
 
+    /** @hide */
+    @Override
+    public int computeVerticalScrollExtent() {
+        return super.computeVerticalScrollExtent();
+    }
+
+    /** @hide */
+    @Override
+    public int computeHorizontalScrollRange() {
+        return super.computeHorizontalScrollRange();
+    }
+
+    /** @hide */
+    @Override
+    public int computeHorizontalScrollOffset() {
+        return super.computeHorizontalScrollOffset();
+    }
+
+    /** @hide */
+    @Override
+    public int computeHorizontalScrollExtent() {
+        return super.computeHorizontalScrollExtent();
+    }
+
     @Override
     protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
         ViewGroup.LayoutParams lp = child.getLayoutParams();
diff --git a/v4/java/android/support/v4/widget/ScrollerCompat.java b/v4/java/android/support/v4/widget/ScrollerCompat.java
index afbf897..3115a41 100644
--- a/v4/java/android/support/v4/widget/ScrollerCompat.java
+++ b/v4/java/android/support/v4/widget/ScrollerCompat.java
@@ -54,6 +54,8 @@
         boolean isOverScrolled(Object scroller);
         int getFinalX(Object scroller);
         int getFinalY(Object scroller);
+        boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+                int minY, int maxY);
     }
 
     static final int CHASE_FRAME_TIME = 16; // ms per target frame
@@ -145,6 +147,12 @@
         public int getFinalY(Object scroller) {
             return ((Scroller) scroller).getFinalY();
         }
+
+        @Override
+        public boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+                int minY, int maxY) {
+            return false;
+        }
     }
 
     static class ScrollerCompatImplGingerbread implements ScrollerCompatImpl {
@@ -233,6 +241,13 @@
         public int getFinalY(Object scroller) {
             return ScrollerCompatGingerbread.getFinalY(scroller);
         }
+
+        @Override
+        public boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+                int minY, int maxY) {
+            return ScrollerCompatGingerbread.springBack(scroller, startX, startY, minX, maxX,
+                    minY, maxY);
+        }
     }
 
     static class ScrollerCompatImplIcs extends ScrollerCompatImplGingerbread {
@@ -423,6 +438,22 @@
     }
 
     /**
+     * Call this when you want to 'spring back' into a valid coordinate range.
+     *
+     * @param startX Starting X coordinate
+     * @param startY Starting Y coordinate
+     * @param minX Minimum valid X value
+     * @param maxX Maximum valid X value
+     * @param minY Minimum valid Y value
+     * @param maxY Maximum valid Y value
+     * @return true if a springback was initiated, false if startX and startY were
+     *          already within the valid range.
+     */
+    public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) {
+        return mImpl.springBack(mScroller, startX, startY, minX, maxX, minY, maxY);
+    }
+
+    /**
      * Stops the animation. Aborting the animation causes the scroller to move to the final x and y
      * position.
      */
diff --git a/v4/java/android/support/v4/widget/SwipeRefreshLayout.java b/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
index d6b35ef..06db6f2 100644
--- a/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -102,6 +102,7 @@
     private boolean mRefreshing = false;
     private int mTouchSlop;
     private float mTotalDragDistance = -1;
+
     // If nested scrolling is enabled, the total amount that needed to be
     // consumed by this as the nested scrolling parent is used in place of the
     // overscroll determined by MOVE events in the onTouch handler
@@ -109,6 +110,8 @@
     private final NestedScrollingParentHelper mNestedScrollingParentHelper;
     private final NestedScrollingChildHelper mNestedScrollingChildHelper;
     private final int[] mParentScrollConsumed = new int[2];
+    private final int[] mParentOffsetInWindow = new int[2];
+    private boolean mNestedScrollInProgress;
 
     private int mMediumAnimationDuration;
     private int mCurrentTargetOffsetTop;
@@ -182,22 +185,34 @@
                         mListener.onRefresh();
                     }
                 }
+                mCurrentTargetOffsetTop = mCircleView.getTop();
             } else {
-                mProgress.stop();
-                mCircleView.setVisibility(View.GONE);
-                setColorViewAlpha(MAX_ALPHA);
-                // Return the circle to its start position
-                if (mScale) {
-                    setAnimationProgress(0 /* animation complete and view is hidden */);
-                } else {
-                    setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop,
-                            true /* requires update */);
-                }
+                reset();
             }
-            mCurrentTargetOffsetTop = mCircleView.getTop();
         }
     };
 
+    private void reset() {
+        mCircleView.clearAnimation();
+        mProgress.stop();
+        mCircleView.setVisibility(View.GONE);
+        setColorViewAlpha(MAX_ALPHA);
+        // Return the circle to its start position
+        if (mScale) {
+            setAnimationProgress(0 /* animation complete and view is hidden */);
+        } else {
+            setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop,
+                    true /* requires update */);
+        }
+        mCurrentTargetOffsetTop = mCircleView.getTop();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        reset();
+    }
+
     private void setColorViewAlpha(int targetAlpha) {
         mCircleView.getBackground().setAlpha(targetAlpha);
         mProgress.setAlpha(targetAlpha);
@@ -654,7 +669,8 @@
             mReturningToStart = false;
         }
 
-        if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing) {
+        if (!isEnabled() || mReturningToStart || canChildScrollUp()
+                || mRefreshing || mNestedScrollInProgress) {
             // Fail fast if we're not in a state where a swipe is possible
             return false;
         }
@@ -728,19 +744,18 @@
 
     @Override
     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
-        if (isEnabled() && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0) {
-            // Dispatch up to the nested parent
-            startNestedScroll(nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL);
-            return true;
-        }
-        return false;
+        return isEnabled() && canChildScrollUp() && !mReturningToStart && !mRefreshing
+                && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
     }
 
     @Override
     public void onNestedScrollAccepted(View child, View target, int axes) {
         // Reset the counter of how much leftover scroll needs to be consumed.
         mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
+        // Dispatch up to the nested parent
+        startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
         mTotalUnconsumed = 0;
+        mNestedScrollInProgress = true;
     }
 
     @Override
@@ -759,6 +774,15 @@
             moveSpinner(mTotalUnconsumed);
         }
 
+        // If a client layout is using a custom start position for the circle
+        // view, they mean to hide it again before scrolling the child view
+        // If we get back to mTotalUnconsumed == 0 and there is more to go, hide
+        // the circle so it isn't exposed if its blocking content is moved
+        if (mUsingCustomStart && dy > 0 && mTotalUnconsumed == 0
+                && Math.abs(dy - consumed[1]) > 0) {
+            mCircleView.setVisibility(View.GONE);
+        }
+
         // Now let our nested parent consume the leftovers
         final int[] parentConsumed = mParentScrollConsumed;
         if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
@@ -775,6 +799,7 @@
     @Override
     public void onStopNestedScroll(View target) {
         mNestedScrollingParentHelper.onStopNestedScroll(target);
+        mNestedScrollInProgress = false;
         // Finish the spinner for nested scrolling if we ever consumed any
         // unconsumed nested scroll
         if (mTotalUnconsumed > 0) {
@@ -786,30 +811,27 @@
     }
 
     @Override
-    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
-            int dyUnconsumed) {
-        if (dyUnconsumed < 0) {
-            dyUnconsumed = Math.abs(dyUnconsumed);
-            mTotalUnconsumed += dyUnconsumed;
+    public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed,
+            final int dxUnconsumed, final int dyUnconsumed) {
+        // Dispatch up to the nested parent first
+        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
+                mParentOffsetInWindow);
+
+        // This is a bit of a hack. Nested scrolling works from the bottom up, and as we are
+        // sometimes between two nested scrolling views, we need a way to be able to know when any
+        // nested scrolling parent has stopped handling events. We do that by using the
+        // 'offset in window 'functionality to see if we have been moved from the event.
+        // This is a decent indication of whether we should take over the event stream or not.
+        final int dy = dyUnconsumed + mParentOffsetInWindow[1];
+        if (dy < 0) {
+            mTotalUnconsumed += Math.abs(dy);
             moveSpinner(mTotalUnconsumed);
         }
-        // Dispatch up to the nested parent
-        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dxConsumed, null);
     }
 
     // NestedScrollingChild
 
     @Override
-    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
-        return false;
-    }
-
-    @Override
-    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
-        return false;
-    }
-
-    @Override
     public void setNestedScrollingEnabled(boolean enabled) {
         mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
     }
@@ -847,6 +869,18 @@
     }
 
     @Override
+    public boolean onNestedPreFling(View target, float velocityX,
+            float velocityY) {
+        return dispatchNestedPreFling(velocityX, velocityY);
+    }
+
+    @Override
+    public boolean onNestedFling(View target, float velocityX, float velocityY,
+            boolean consumed) {
+        return dispatchNestedFling(velocityX, velocityY, consumed);
+    }
+
+    @Override
     public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
         return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
     }
@@ -943,12 +977,13 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         final int action = MotionEventCompat.getActionMasked(ev);
+        int pointerIndex = -1;
 
         if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
             mReturningToStart = false;
         }
 
-        if (!isEnabled() || mReturningToStart || canChildScrollUp()) {
+        if (!isEnabled() || mReturningToStart || canChildScrollUp() || mNestedScrollInProgress) {
             // Fail fast if we're not in a state where a swipe is possible
             return false;
         }
@@ -960,7 +995,7 @@
                 break;
 
             case MotionEvent.ACTION_MOVE: {
-                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+                pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
                 if (pointerIndex < 0) {
                     Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
                     return false;
@@ -978,8 +1013,12 @@
                 break;
             }
             case MotionEventCompat.ACTION_POINTER_DOWN: {
-                final int index = MotionEventCompat.getActionIndex(ev);
-                mActivePointerId = MotionEventCompat.getPointerId(ev, index);
+                pointerIndex = MotionEventCompat.getActionIndex(ev);
+                if (pointerIndex < 0) {
+                    Log.e(LOG_TAG, "Got ACTION_POINTER_DOWN event but have an invalid action index.");
+                    return false;
+                }
+                mActivePointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
                 break;
             }
 
@@ -987,15 +1026,13 @@
                 onSecondaryPointerUp(ev);
                 break;
 
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL: {
-                if (mActivePointerId == INVALID_POINTER) {
-                    if (action == MotionEvent.ACTION_UP) {
-                        Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
-                    }
+            case MotionEvent.ACTION_UP: {
+                pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+                if (pointerIndex < 0) {
+                    Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
                     return false;
                 }
-                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+
                 final float y = MotionEventCompat.getY(ev, pointerIndex);
                 final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
                 mIsBeingDragged = false;
@@ -1003,6 +1040,8 @@
                 mActivePointerId = INVALID_POINTER;
                 return false;
             }
+            case MotionEvent.ACTION_CANCEL:
+                return false;
         }
 
         return true;
@@ -1020,18 +1059,6 @@
         mCircleView.startAnimation(mAnimateToCorrectPosition);
     }
 
-    private void peek(int from, AnimationListener listener) {
-        mFrom = from;
-        mPeek.reset();
-        mPeek.setDuration(500);
-        mPeek.setInterpolator(mDecelerateInterpolator);
-        if (listener != null) {
-            mCircleView.setAnimationListener(listener);
-        }
-        mCircleView.clearAnimation();
-        mCircleView.startAnimation(mPeek);
-    }
-
     private void animateOffsetToStartPosition(int from, AnimationListener listener) {
         if (mScale) {
             // Scale the item back down
@@ -1066,23 +1093,6 @@
         }
     };
 
-    private final Animation mPeek = new Animation() {
-        @Override
-        public void applyTransformation(float interpolatedTime, Transformation t) {
-            int targetTop = 0;
-            int endTarget = 0;
-            if (!mUsingCustomStart) {
-                endTarget = (int) (mSpinnerFinalOffset - Math.abs(mOriginalOffsetTop));
-            } else {
-                endTarget = (int) mSpinnerFinalOffset; //mSpinnerFinalOffset;
-            }
-            targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
-            int offset = targetTop - mCircleView.getTop();
-            setTargetOffsetTopAndBottom(offset, false /* requires update */);
-            mProgress.setArrowScale(1 - interpolatedTime);
-        }
-    };
-
     private void moveToStart(float interpolatedTime) {
         int targetTop = 0;
         targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
diff --git a/v4/java/android/support/v4/widget/TextViewCompat.java b/v4/java/android/support/v4/widget/TextViewCompat.java
index c31196a..621ee66 100644
--- a/v4/java/android/support/v4/widget/TextViewCompat.java
+++ b/v4/java/android/support/v4/widget/TextViewCompat.java
@@ -18,6 +18,7 @@
 
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.support.annotation.IdRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.widget.TextView;
@@ -29,26 +30,23 @@
 public class TextViewCompat {
 
     // Hide constructor
-    private TextViewCompat() {
-    }
+    private TextViewCompat() {}
 
     interface TextViewCompatImpl {
-
-        public void setCompoundDrawablesRelative(@NonNull TextView textView,
+        void setCompoundDrawablesRelative(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom);
-
-        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
+        void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom);
-
-        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
+        void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
                 int start, int top, int end, int bottom);
-
+        int getMaxLines(TextView textView);
+        int getMinLines(TextView textView);
+        void setTextAppearance(@NonNull TextView textView, @IdRes int resId);
     }
 
     static class BaseTextViewCompatImpl implements TextViewCompatImpl {
-
         @Override
         public void setCompoundDrawablesRelative(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@@ -69,11 +67,36 @@
             textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
         }
 
+        @Override
+        public int getMaxLines(TextView textView) {
+            return TextViewCompatDonut.getMaxLines(textView);
+        }
+
+        @Override
+        public int getMinLines(TextView textView) {
+            return TextViewCompatDonut.getMinLines(textView);
+        }
+
+        @Override
+        public void setTextAppearance(TextView textView, int resId) {
+            TextViewCompatDonut.setTextAppearance(textView, resId);
+        }
     }
 
-    static class JbMr1TextViewCompatImpl extends BaseTextViewCompatImpl {
+    static class JbTextViewCompatImpl extends BaseTextViewCompatImpl {
+        @Override
+        public int getMaxLines(TextView textView) {
+            return TextViewCompatJb.getMaxLines(textView);
+        }
 
         @Override
+        public int getMinLines(TextView textView) {
+            return TextViewCompatJb.getMinLines(textView);
+        }
+    }
+
+    static class JbMr1TextViewCompatImpl extends JbTextViewCompatImpl {
+        @Override
         public void setCompoundDrawablesRelative(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
                 @Nullable Drawable bottom) {
@@ -94,11 +117,9 @@
             TextViewCompatJbMr1.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
                     start, top, end, bottom);
         }
-
     }
 
     static class JbMr2TextViewCompatImpl extends JbMr1TextViewCompatImpl {
-
         @Override
         public void setCompoundDrawablesRelative(@NonNull TextView textView,
                 @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@@ -123,14 +144,25 @@
         }
     }
 
+    static class Api23TextViewCompatImpl extends JbMr2TextViewCompatImpl {
+        @Override
+        public void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+            TextViewCompatApi23.setTextAppearance(textView, resId);
+        }
+    }
+
     static final TextViewCompatImpl IMPL;
 
     static {
         final int version = Build.VERSION.SDK_INT;
-        if (version >= 18) {
+        if (version >= 23) {
+            IMPL = new Api23TextViewCompatImpl();
+        } else if (version >= 18) {
             IMPL = new JbMr2TextViewCompatImpl();
         } else if (version >= 17) {
             IMPL = new JbMr1TextViewCompatImpl();
+        } else if (version >= 16) {
+            IMPL = new JbTextViewCompatImpl();
         } else {
             IMPL = new BaseTextViewCompatImpl();
         }
@@ -200,4 +232,34 @@
         IMPL.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end, bottom);
     }
 
+    /**
+     * Returns the maximum number of lines displayed in the given TextView, or -1 if the maximum
+     * height was set in pixels instead.
+     */
+    public static int getMaxLines(@NonNull TextView textView) {
+        return IMPL.getMaxLines(textView);
+    }
+
+    /**
+     * Returns the minimum number of lines displayed in the given TextView, or -1 if the minimum
+     * height was set in pixels instead.
+     */
+    public static int getMinLines(@NonNull TextView textView) {
+        return IMPL.getMinLines(textView);
+    }
+
+    /**
+     * Sets the text appearance from the specified style resource.
+     * <p>
+     * Use a framework-defined {@code TextAppearance} style like
+     * {@link android.R.style#TextAppearance_Material_Body1 @android:style/TextAppearance.Material.Body1}
+     * or see {@link android.R.styleable#TextAppearance TextAppearance} for the
+     * set of attributes that can be used in a custom style.
+     *
+     * @param textView The TextView against which to invoke the method.
+     * @param resId    The resource identifier of the style to apply.
+     */
+    public static void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+        IMPL.setTextAppearance(textView, resId);
+    }
 }
diff --git a/v4/java/android/support/v4/widget/TextViewCompatDonut.java b/v4/java/android/support/v4/widget/TextViewCompatDonut.java
new file mode 100644
index 0000000..ba155fe
--- /dev/null
+++ b/v4/java/android/support/v4/widget/TextViewCompatDonut.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.widget;
+
+import android.util.Log;
+import android.widget.TextView;
+
+import java.lang.reflect.Field;
+
+class TextViewCompatDonut {
+
+    private static final String LOG_TAG = "TextViewCompatDonut";
+    private static final int LINES = 1;
+
+    private static Field sMaximumField;
+    private static boolean sMaximumFieldFetched;
+    private static Field sMaxModeField;
+    private static boolean sMaxModeFieldFetched;
+
+    private static Field sMinimumField;
+    private static boolean sMinimumFieldFetched;
+    private static Field sMinModeField;
+    private static boolean sMinModeFieldFetched;
+
+    static int getMaxLines(TextView textView) {
+        if (!sMaxModeFieldFetched) {
+            sMaxModeField = retrieveField("mMaxMode");
+            sMaxModeFieldFetched = true;
+        }
+        if (sMaxModeField != null && retrieveIntFromField(sMaxModeField, textView) == LINES) {
+            // If the max mode is using lines, we can grab the maximum value
+            if (!sMaximumFieldFetched) {
+                sMaximumField = retrieveField("mMaximum");
+                sMaximumFieldFetched = true;
+            }
+            if (sMaximumField != null) {
+                return retrieveIntFromField(sMaximumField, textView);
+            }
+        }
+        return -1;
+    }
+
+    static int getMinLines(TextView textView) {
+        if (!sMinModeFieldFetched) {
+            sMinModeField = retrieveField("mMinMode");
+            sMinModeFieldFetched = true;
+        }
+        if (sMinModeField != null && retrieveIntFromField(sMinModeField, textView) == LINES) {
+            // If the min mode is using lines, we can grab the maximum value
+            if (!sMinimumFieldFetched) {
+                sMinimumField = retrieveField("mMinimum");
+                sMinimumFieldFetched = true;
+            }
+            if (sMinimumField != null) {
+                return retrieveIntFromField(sMinimumField, textView);
+            }
+        }
+        return -1;
+    }
+
+    private static Field retrieveField(String fieldName) {
+        Field field = null;
+        try {
+            field = TextView.class.getDeclaredField(fieldName);
+            field.setAccessible(true);
+        } catch (NoSuchFieldException e) {
+            Log.e(LOG_TAG, "Could not retrieve " + fieldName + " field.");
+        }
+        return field;
+    }
+
+    private static int retrieveIntFromField(Field field, TextView textView) {
+        try {
+            return field.getInt(textView);
+        } catch (IllegalAccessException e) {
+            Log.d(LOG_TAG, "Could not retrieve value of " + field.getName() + " field.");
+        }
+        return -1;
+    }
+
+    static void setTextAppearance(TextView textView, int resId) {
+        textView.setTextAppearance(textView.getContext(), resId);
+    }
+}
diff --git a/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java b/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
index fcdf8b5..d5b675b4d 100644
--- a/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
+++ b/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
@@ -25,7 +25,7 @@
 /**
  * Jellybean MR1 - specific TextUtils API access.
  */
-public class TextUtilsCompatJellybeanMr1 {
+class TextUtilsCompatJellybeanMr1 {
     @NonNull
     public static String htmlEncode(@NonNull String s) {
         return TextUtils.htmlEncode(s);
diff --git a/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java b/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
index 38b6778..be3555e 100644
--- a/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
+++ b/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
@@ -28,9 +28,7 @@
 import android.view.View;
 import android.view.ViewTreeObserver;
 
-class TransportMediatorJellybeanMR2
-        implements RemoteControlClient.OnGetPlaybackPositionListener,
-        RemoteControlClient.OnPlaybackPositionUpdateListener {
+class TransportMediatorJellybeanMR2 {
     final Context mContext;
     final AudioManager mAudioManager;
     final View mTargetView;
@@ -75,7 +73,20 @@
             mTransportCallback.handleAudioFocusChange(focusChange);
         }
     };
-
+    final RemoteControlClient.OnGetPlaybackPositionListener mGetPlaybackPositionListener
+            = new RemoteControlClient.OnGetPlaybackPositionListener() {
+                @Override
+                public long onGetPlaybackPosition() {
+                    return mTransportCallback.getPlaybackPosition();
+                }
+            };
+    final RemoteControlClient.OnPlaybackPositionUpdateListener mPlaybackPositionUpdateListener
+            = new RemoteControlClient.OnPlaybackPositionUpdateListener() {
+                public void onPlaybackPositionUpdate(long newPositionMs) {
+                    mTransportCallback.playbackPositionUpdate(newPositionMs);
+                }
+            };
+ 
     PendingIntent mPendingIntent;
     RemoteControlClient mRemoteControl;
     boolean mFocused;
@@ -112,8 +123,8 @@
         mPendingIntent = PendingIntent.getBroadcast(mContext, 0, mIntent,
                 PendingIntent.FLAG_CANCEL_CURRENT);
         mRemoteControl = new RemoteControlClient(mPendingIntent);
-        mRemoteControl.setOnGetPlaybackPositionListener(this);
-        mRemoteControl.setPlaybackPositionUpdateListener(this);
+        mRemoteControl.setOnGetPlaybackPositionListener(mGetPlaybackPositionListener);
+        mRemoteControl.setPlaybackPositionUpdateListener(mPlaybackPositionUpdateListener);
     }
 
     void gainFocus() {
@@ -145,16 +156,6 @@
         }
     }
 
-    @Override
-    public long onGetPlaybackPosition() {
-        return mTransportCallback.getPlaybackPosition();
-    }
-
-    @Override
-    public void onPlaybackPositionUpdate(long newPositionMs) {
-        mTransportCallback.playbackPositionUpdate(newPositionMs);
-    }
-
     public void refreshState(boolean playing, long position, int transportControls) {
         if (mRemoteControl != null) {
             mRemoteControl.setPlaybackState(playing ? RemoteControlClient.PLAYSTATE_PLAYING
diff --git a/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java b/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
index 1c5dca7..8ceb38c 100644
--- a/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
+++ b/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
@@ -16,28 +16,56 @@
 package android.support.v4.media.session;
 
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.RemoteControlClient;
+import android.util.Log;
 import android.os.SystemClock;
 
-public class MediaSessionCompatApi18 {
+class MediaSessionCompatApi18 {
+    private static final String TAG = "MediaSessionCompatApi18";
+
     /***** PlaybackState actions *****/
     private static final long ACTION_SEEK_TO = 1 << 8;
 
+    private static boolean sIsMbrPendingIntentSupported = true;
+
     public static Object createPlaybackPositionUpdateListener(
             MediaSessionCompatApi14.Callback callback) {
         return new OnPlaybackPositionUpdateListener<MediaSessionCompatApi14.Callback>(callback);
     }
 
-    public static void registerMediaButtonEventReceiver(Context context, PendingIntent pi) {
+    public static void registerMediaButtonEventReceiver(Context context, PendingIntent pi,
+            ComponentName cn) {
         AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        am.registerMediaButtonEventReceiver(pi);
+
+        // Some Android implementations are not able to register a media button event receiver
+        // using a PendingIntent but need a ComponentName instead. These will raise a
+        // NullPointerException.
+        if (sIsMbrPendingIntentSupported) {
+            try {
+                am.registerMediaButtonEventReceiver(pi);
+            } catch (NullPointerException e) {
+                Log.w(TAG, "Unable to register media button event receiver with "
+                        + "PendingIntent, falling back to ComponentName.");
+                sIsMbrPendingIntentSupported = false;
+            }
+        }
+
+        if (!sIsMbrPendingIntentSupported) {
+          am.registerMediaButtonEventReceiver(cn);
+        }
     }
 
-    public static void unregisterMediaButtonEventReceiver(Context context, PendingIntent pi) {
+    public static void unregisterMediaButtonEventReceiver(Context context, PendingIntent pi,
+            ComponentName cn) {
         AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        am.unregisterMediaButtonEventReceiver(pi);
+        if (sIsMbrPendingIntentSupported) {
+            am.unregisterMediaButtonEventReceiver(pi);
+        } else {
+            am.unregisterMediaButtonEventReceiver(cn);
+        }
     }
 
     public static void setState(Object rccObj, int state, long position, float speed,
diff --git a/v4/jellybean/android/support/v4/widget/TextViewCompatJb.java b/v4/jellybean/android/support/v4/widget/TextViewCompatJb.java
new file mode 100644
index 0000000..1658874
--- /dev/null
+++ b/v4/jellybean/android/support/v4/widget/TextViewCompatJb.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.widget;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.TextView;
+
+class TextViewCompatJb {
+    static int getMaxLines(TextView textView) {
+        return textView.getMaxLines();
+    }
+
+    static int getMinLines(TextView textView) {
+        return textView.getMinLines();
+    }
+}
diff --git a/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java b/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
index 61039d3..f3c19e2 100644
--- a/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
+++ b/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
@@ -15,14 +15,13 @@
  */
 package android.support.v4.media.session;
 
-import android.graphics.Bitmap;
 import android.media.MediaMetadataEditor;
 import android.media.MediaMetadataRetriever;
 import android.media.Rating;
 import android.media.RemoteControlClient;
 import android.os.Bundle;
 
-public class MediaSessionCompatApi19 {
+class MediaSessionCompatApi19 {
     /***** PlaybackState actions *****/
     private static final long ACTION_SET_RATING = 1 << 7;
 
diff --git a/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java b/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
index 5439972..64f1969 100644
--- a/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
+++ b/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
@@ -22,12 +22,16 @@
 
     public static void setUpdateListener(final View view,
             final ViewPropertyAnimatorUpdateListener listener) {
-        view.animate().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                listener.onAnimationUpdate(view);
-            }
-        });
+        ValueAnimator.AnimatorUpdateListener wrapped = null;
+        if (listener != null) {
+            wrapped = new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                    listener.onAnimationUpdate(view);
+                }
+            };
+        }
+        view.animate().setUpdateListener(wrapped);
     }
 
 }
diff --git a/v4/tests/AndroidManifest.xml b/v4/tests/AndroidManifest.xml
new file mode 100644
index 0000000..556c885
--- /dev/null
+++ b/v4/tests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.v4.test">
+    <uses-sdk android:minSdkVersion="4" tools:overrideLibrary="android.support.test,
+            android.support.test.espresso, android.support.test.espresso.idling"/>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
+        <activity android:name="android.support.v4.widget.TestActivity"/>
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.support.v4.test"
+                     />
+</manifest>
diff --git a/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java b/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java
index 855cdba..56cb6fb 100644
--- a/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java
+++ b/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java
@@ -17,9 +17,9 @@
 package android.support.v4.graphics;
 
 import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
 import android.test.AndroidTestCase;
 
+import java.lang.Integer;
 import java.util.ArrayList;
 
 /**
@@ -31,21 +31,31 @@
     private static final float ALLOWED_OFFSET_HUE = 360 * 0.005f;
     private static final float ALLOWED_OFFSET_SATURATION = 0.005f;
     private static final float ALLOWED_OFFSET_LIGHTNESS = 0.005f;
+    private static final float ALLOWED_OFFSET_MIN_ALPHA = 0.01f;
 
     private static final int ALLOWED_OFFSET_RGB_COMPONENT = 2;
 
     private static final ArrayList<TestEntry> sEntryList = new ArrayList<>();
 
     static {
-        sEntryList.add(new TestEntry(Color.BLACK).setHsl(0f, 0f, 0f));
-        sEntryList.add(new TestEntry(Color.WHITE).setHsl(0f, 0f, 1f));
-        sEntryList.add(new TestEntry(Color.BLUE).setHsl(240f, 1f, 0.5f));
-        sEntryList.add(new TestEntry(Color.GREEN).setHsl(120f, 1f, 0.5f));
-        sEntryList.add(new TestEntry(Color.RED).setHsl(0f, 1f, 0.5f));
-        sEntryList.add(new TestEntry(Color.CYAN).setHsl(180f, 1f, 0.5f));
-        sEntryList.add(new TestEntry(0x2196F3).setHsl(207f, 0.9f, 0.54f));
-        sEntryList.add(new TestEntry(0xD1C4E9).setHsl(261f, 0.46f, 0.84f));
-        sEntryList.add(new TestEntry(0x311B92).setHsl(251.09f, 0.687f, 0.339f));
+        sEntryList.add(new TestEntry(Color.BLACK).setHsl(0f, 0f, 0f)
+                .setWhiteMinAlpha30(0.35f).setWhiteMinAlpha45(0.46f));
+        sEntryList.add(new TestEntry(Color.WHITE).setHsl(0f, 0f, 1f)
+                .setBlackMinAlpha30(0.42f).setBlackMinAlpha45(0.54f));
+        sEntryList.add(new TestEntry(Color.BLUE).setHsl(240f, 1f, 0.5f)
+                .setWhiteMinAlpha30(0.55f).setWhiteMinAlpha45(0.71f));
+        sEntryList.add(new TestEntry(Color.GREEN).setHsl(120f, 1f, 0.5f)
+                .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
+        sEntryList.add(new TestEntry(Color.RED).setHsl(0f, 1f, 0.5f)
+                .setWhiteMinAlpha30(0.84f).setBlackMinAlpha30(0.55f).setBlackMinAlpha45(0.78f));
+        sEntryList.add(new TestEntry(Color.CYAN).setHsl(180f, 1f, 0.5f)
+                .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
+        sEntryList.add(new TestEntry(0xFF2196F3).setHsl(207f, 0.9f, 0.54f)
+                .setBlackMinAlpha30(0.52f).setWhiteMinAlpha30(0.97f).setBlackMinAlpha45(0.7f));
+        sEntryList.add(new TestEntry(0xFFD1C4E9).setHsl(261f, 0.46f, 0.84f)
+                .setBlackMinAlpha30(0.45f).setBlackMinAlpha45(0.58f));
+        sEntryList.add(new TestEntry(0xFF311B92).setHsl(251.09f, 0.687f, 0.339f)
+                .setWhiteMinAlpha30(0.39f).setWhiteMinAlpha45(0.54f));
     }
 
     public void testToHSL() {
@@ -72,6 +82,28 @@
         }
     }
 
+    public void testMinAlphas() {
+        for (TestEntry entry : sEntryList) {
+            testMinAlpha("Black title", entry.rgb, entry.blackMinAlpha30,
+                    ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 3.0f));
+            testMinAlpha("Black body", entry.rgb, entry.blackMinAlpha45,
+                    ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 4.5f));
+            testMinAlpha("White title", entry.rgb, entry.whiteMinAlpha30,
+                    ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 3.0f));
+            testMinAlpha("White body", entry.rgb, entry.whiteMinAlpha45,
+                    ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 4.5f));
+        }
+    }
+
+    private static void testMinAlpha(String title, int color, float expected, int actual) {
+        final String message = title + " text within error for #" + Integer.toHexString(color);
+        if (expected < 0) {
+            assertEquals(message, actual, -1);
+        } else {
+            assertClose(message, expected, actual / 255f, ALLOWED_OFFSET_MIN_ALPHA);
+        }
+    }
+
     private static void assertClose(String message, float expected, float actual,
             float allowedOffset) {
         StringBuilder sb = new StringBuilder(message);
@@ -114,6 +146,10 @@
     private static class TestEntry {
         final int rgb;
         final float[] hsl = new float[3];
+        float blackMinAlpha45 = -1;
+        float blackMinAlpha30 = -1;
+        float whiteMinAlpha45 = -1;
+        float whiteMinAlpha30 = -1;
 
         TestEntry(int rgb) {
             this.rgb = rgb;
@@ -125,5 +161,25 @@
             hsl[2] = l;
             return this;
         }
+
+        TestEntry setBlackMinAlpha30(float minAlpha) {
+            blackMinAlpha30 = minAlpha;
+            return this;
+        }
+
+        TestEntry setBlackMinAlpha45(float minAlpha) {
+            blackMinAlpha45 = minAlpha;
+            return this;
+        }
+
+        TestEntry setWhiteMinAlpha30(float minAlpha) {
+            whiteMinAlpha30 = minAlpha;
+            return this;
+        }
+
+        TestEntry setWhiteMinAlpha45(float minAlpha) {
+            whiteMinAlpha45 = minAlpha;
+            return this;
+        }
     }
 }
\ No newline at end of file
diff --git a/v4/tests/java/android/support/v4/widget/TestActivity.java b/v4/tests/java/android/support/v4/widget/TestActivity.java
new file mode 100644
index 0000000..9ab5188
--- /dev/null
+++ b/v4/tests/java/android/support/v4/widget/TestActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+public class TestActivity extends Activity {
+    FrameLayout mContainer;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContainer = new FrameLayout(this);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        setContentView(mContainer);
+    }
+}
diff --git a/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java b/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java
new file mode 100644
index 0000000..a7d2339
--- /dev/null
+++ b/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+
+package android.support.v4.widget;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.v4.widget.TextViewCompat;
+import android.util.Log;
+import android.widget.TextView;
+
+import android.support.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+public class TextViewCompatTest extends ActivityInstrumentationTestCase2<TestActivity> {
+    private boolean mDebug;
+
+    Throwable mainThreadException;
+
+    Thread mInstrumentationThread;
+
+    public TextViewCompatTest() {
+        super("android.support.v4.widget", TestActivity.class);
+        mDebug = false;
+    }
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mInstrumentationThread = Thread.currentThread();
+
+        // Note that injectInstrumentation was added in v5. Since this is v4 we have to use
+        // the misspelled (and deprecated) inject API.
+        injectInsrumentation(InstrumentationRegistry.getInstrumentation());
+    }
+
+    @After
+    @Override
+    public void tearDown() throws Exception {
+        getInstrumentation().waitForIdleSync();
+        super.tearDown();
+    }
+
+    @Test
+    public void testMaxLines() throws Throwable {
+        final TextView textView = new TextView(getActivity());
+        textView.setMaxLines(4);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().mContainer.addView(textView);
+            }
+        });
+
+        assertEquals("Max lines must match", TextViewCompat.getMaxLines(textView), 4);
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
similarity index 60%
copy from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
copy to v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
index 8eea38d..7366127 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,17 +14,11 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v4.widget.test;
 
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
 
-/**
- * @hide
- */
-public class TintInfo {
-    public ColorStateList mTintList;
-    public PorterDuff.Mode mTintMode;
-    public boolean mHasTintMode;
-    public boolean mHasTintList;
+import android.app.Activity;
+
+public class TextViewTestActivity extends Activity {
+
 }
diff --git a/v7/appcompat/api/23.txt b/v7/appcompat/api/23.0.0.txt
similarity index 100%
rename from v7/appcompat/api/23.txt
rename to v7/appcompat/api/23.0.0.txt
diff --git a/v7/appcompat/api/23.1.0.txt b/v7/appcompat/api/23.1.0.txt
new file mode 100644
index 0000000..2df0ec0
--- /dev/null
+++ b/v7/appcompat/api/23.1.0.txt
@@ -0,0 +1,2081 @@
+package android.support.v7.app {
+
+  public abstract class ActionBar {
+    ctor public ActionBar();
+    method public abstract void addOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, boolean);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int);
+    method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int, boolean);
+    method public abstract android.view.View getCustomView();
+    method public abstract int getDisplayOptions();
+    method public float getElevation();
+    method public abstract int getHeight();
+    method public int getHideOffset();
+    method public abstract deprecated int getNavigationItemCount();
+    method public abstract deprecated int getNavigationMode();
+    method public abstract deprecated int getSelectedNavigationIndex();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab getSelectedTab();
+    method public abstract java.lang.CharSequence getSubtitle();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab getTabAt(int);
+    method public abstract deprecated int getTabCount();
+    method public android.content.Context getThemedContext();
+    method public abstract java.lang.CharSequence getTitle();
+    method public abstract void hide();
+    method public boolean isHideOnContentScrollEnabled();
+    method public abstract boolean isShowing();
+    method public abstract deprecated android.support.v7.app.ActionBar.Tab newTab();
+    method public abstract deprecated void removeAllTabs();
+    method public abstract void removeOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract deprecated void removeTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract deprecated void removeTabAt(int);
+    method public abstract deprecated void selectTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setCustomView(android.view.View);
+    method public abstract void setCustomView(android.view.View, android.support.v7.app.ActionBar.LayoutParams);
+    method public abstract void setCustomView(int);
+    method public abstract void setDisplayHomeAsUpEnabled(boolean);
+    method public abstract void setDisplayOptions(int);
+    method public abstract void setDisplayOptions(int, int);
+    method public abstract void setDisplayShowCustomEnabled(boolean);
+    method public abstract void setDisplayShowHomeEnabled(boolean);
+    method public abstract void setDisplayShowTitleEnabled(boolean);
+    method public abstract void setDisplayUseLogoEnabled(boolean);
+    method public void setElevation(float);
+    method public void setHideOffset(int);
+    method public void setHideOnContentScrollEnabled(boolean);
+    method public void setHomeActionContentDescription(java.lang.CharSequence);
+    method public void setHomeActionContentDescription(int);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setHomeButtonEnabled(boolean);
+    method public abstract void setIcon(int);
+    method public abstract void setIcon(android.graphics.drawable.Drawable);
+    method public abstract deprecated void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.support.v7.app.ActionBar.OnNavigationListener);
+    method public abstract void setLogo(int);
+    method public abstract void setLogo(android.graphics.drawable.Drawable);
+    method public abstract deprecated void setNavigationMode(int);
+    method public abstract deprecated void setSelectedNavigationItem(int);
+    method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setSubtitle(java.lang.CharSequence);
+    method public abstract void setSubtitle(int);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract void setTitle(int);
+    method public abstract void show();
+    field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
+    field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
+    field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
+    field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
+    field public static final int DISPLAY_USE_LOGO = 1; // 0x1
+    field public static final deprecated int NAVIGATION_MODE_LIST = 1; // 0x1
+    field public static final deprecated int NAVIGATION_MODE_STANDARD = 0; // 0x0
+    field public static final deprecated int NAVIGATION_MODE_TABS = 2; // 0x2
+  }
+
+  public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionBar.LayoutParams(int, int);
+    ctor public ActionBar.LayoutParams(int, int, int);
+    ctor public ActionBar.LayoutParams(int);
+    ctor public ActionBar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+    ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
+    field public int gravity;
+  }
+
+  public static abstract interface ActionBar.OnMenuVisibilityListener {
+    method public abstract void onMenuVisibilityChanged(boolean);
+  }
+
+  public static abstract deprecated interface ActionBar.OnNavigationListener {
+    method public abstract boolean onNavigationItemSelected(int, long);
+  }
+
+  public static abstract deprecated class ActionBar.Tab {
+    ctor public ActionBar.Tab();
+    method public abstract java.lang.CharSequence getContentDescription();
+    method public abstract android.view.View getCustomView();
+    method public abstract android.graphics.drawable.Drawable getIcon();
+    method public abstract int getPosition();
+    method public abstract java.lang.Object getTag();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract void select();
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(android.view.View);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setTabListener(android.support.v7.app.ActionBar.TabListener);
+    method public abstract android.support.v7.app.ActionBar.Tab setTag(java.lang.Object);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(int);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static abstract deprecated interface ActionBar.TabListener {
+    method public abstract void onTabReselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabSelected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabUnselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+  }
+
+  public deprecated class ActionBarActivity extends android.support.v7.app.AppCompatActivity {
+    ctor public ActionBarActivity();
+  }
+
+  public class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int);
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, android.support.v7.widget.Toolbar, int, int);
+    method public android.view.View.OnClickListener getToolbarNavigationClickListener();
+    method public boolean isDrawerIndicatorEnabled();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void setDrawerIndicatorEnabled(boolean);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
+    method public void syncState();
+  }
+
+  public static abstract interface ActionBarDrawerToggle.Delegate {
+    method public abstract android.content.Context getActionBarThemedContext();
+    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+    method public abstract boolean isNavigationVisible();
+    method public abstract void setActionBarDescription(int);
+    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+  }
+
+  public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+    method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+  }
+
+  public class AlertDialog extends android.support.v7.app.AppCompatDialog implements android.content.DialogInterface {
+    ctor protected AlertDialog(android.content.Context);
+    ctor protected AlertDialog(android.content.Context, int);
+    ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.widget.Button getButton(int);
+    method public android.widget.ListView getListView();
+    method public void setButton(int, java.lang.CharSequence, android.os.Message);
+    method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public void setCustomTitle(android.view.View);
+    method public void setIcon(int);
+    method public void setIcon(android.graphics.drawable.Drawable);
+    method public void setIconAttribute(int);
+    method public void setMessage(java.lang.CharSequence);
+    method public void setView(android.view.View);
+    method public void setView(android.view.View, int, int, int, int);
+  }
+
+  public static class AlertDialog.Builder {
+    ctor public AlertDialog.Builder(android.content.Context);
+    ctor public AlertDialog.Builder(android.content.Context, int);
+    method public android.support.v7.app.AlertDialog create();
+    method public android.content.Context getContext();
+    method public android.support.v7.app.AlertDialog.Builder setAdapter(android.widget.ListAdapter, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setCancelable(boolean);
+    method public android.support.v7.app.AlertDialog.Builder setCursor(android.database.Cursor, android.content.DialogInterface.OnClickListener, java.lang.String);
+    method public android.support.v7.app.AlertDialog.Builder setCustomTitle(android.view.View);
+    method public android.support.v7.app.AlertDialog.Builder setIcon(int);
+    method public android.support.v7.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.support.v7.app.AlertDialog.Builder setIconAttribute(int);
+    method public android.support.v7.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public android.support.v7.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMessage(int);
+    method public android.support.v7.app.AlertDialog.Builder setMessage(java.lang.CharSequence);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(int, boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(java.lang.CharSequence[], boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, java.lang.String, java.lang.String, android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNegativeButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNegativeButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNeutralButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setNeutralButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnCancelListener(android.content.DialogInterface.OnCancelListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnDismissListener(android.content.DialogInterface.OnDismissListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public android.support.v7.app.AlertDialog.Builder setOnKeyListener(android.content.DialogInterface.OnKeyListener);
+    method public android.support.v7.app.AlertDialog.Builder setPositiveButton(int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setPositiveButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(int, int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, java.lang.String, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(java.lang.CharSequence[], int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.widget.ListAdapter, int, android.content.DialogInterface.OnClickListener);
+    method public android.support.v7.app.AlertDialog.Builder setTitle(int);
+    method public android.support.v7.app.AlertDialog.Builder setTitle(java.lang.CharSequence);
+    method public android.support.v7.app.AlertDialog.Builder setView(int);
+    method public android.support.v7.app.AlertDialog.Builder setView(android.view.View);
+    method public android.support.v7.app.AlertDialog show();
+  }
+
+  public class AppCompatActivity extends android.support.v4.app.FragmentActivity implements android.support.v7.app.ActionBarDrawerToggle.DelegateProvider android.support.v7.app.AppCompatCallback {
+    ctor public AppCompatActivity();
+    method public android.support.v7.app.AppCompatDelegate getDelegate();
+    method public android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+    method public android.support.v7.app.ActionBar getSupportActionBar();
+    method public android.content.Intent getSupportParentActivityIntent();
+    method public void onCreateSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+    method public final boolean onMenuItemSelected(int, android.view.MenuItem);
+    method public void onPrepareSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+    method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public deprecated void onSupportContentChanged();
+    method public boolean onSupportNavigateUp();
+    method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public void setSupportActionBar(android.support.v7.widget.Toolbar);
+    method public deprecated void setSupportProgress(int);
+    method public deprecated void setSupportProgressBarIndeterminate(boolean);
+    method public deprecated void setSupportProgressBarIndeterminateVisibility(boolean);
+    method public deprecated void setSupportProgressBarVisibility(boolean);
+    method public android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public void supportNavigateUpTo(android.content.Intent);
+    method public boolean supportRequestWindowFeature(int);
+    method public boolean supportShouldUpRecreateTask(android.content.Intent);
+  }
+
+  public abstract interface AppCompatCallback {
+    method public abstract void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public abstract void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public abstract android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+  }
+
+  public abstract class AppCompatDelegate {
+    method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Activity, android.support.v7.app.AppCompatCallback);
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Dialog, android.support.v7.app.AppCompatCallback);
+    method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+    method public abstract android.view.MenuInflater getMenuInflater();
+    method public abstract android.support.v7.app.ActionBar getSupportActionBar();
+    method public abstract boolean hasWindowFeature(int);
+    method public abstract void installViewFactory();
+    method public abstract void invalidateOptionsMenu();
+    method public abstract boolean isHandleNativeActionModesEnabled();
+    method public abstract void onConfigurationChanged(android.content.res.Configuration);
+    method public abstract void onCreate(android.os.Bundle);
+    method public abstract void onDestroy();
+    method public abstract void onPostCreate(android.os.Bundle);
+    method public abstract void onPostResume();
+    method public abstract void onStop();
+    method public abstract boolean requestWindowFeature(int);
+    method public abstract void setContentView(android.view.View);
+    method public abstract void setContentView(int);
+    method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract void setHandleNativeActionModesEnabled(boolean);
+    method public abstract void setSupportActionBar(android.support.v7.widget.Toolbar);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+    field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
+    field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
+  }
+
+  public class AppCompatDialog extends android.app.Dialog implements android.support.v7.app.AppCompatCallback {
+    ctor public AppCompatDialog(android.content.Context);
+    ctor public AppCompatDialog(android.content.Context, int);
+    ctor protected AppCompatDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.support.v7.app.AppCompatDelegate getDelegate();
+    method public android.support.v7.app.ActionBar getSupportActionBar();
+    method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public boolean supportRequestWindowFeature(int);
+  }
+
+  public class AppCompatDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public AppCompatDialogFragment();
+  }
+
+  public class NotificationCompat extends android.support.v4.app.NotificationCompat {
+    ctor public NotificationCompat();
+  }
+
+  public static class NotificationCompat.Builder extends android.support.v4.app.NotificationCompat.Builder {
+    ctor public NotificationCompat.Builder(android.content.Context);
+  }
+
+  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);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setCancelButtonIntent(android.app.PendingIntent);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setShowActionsInCompactView(int...);
+    method public android.support.v7.app.NotificationCompat.MediaStyle setShowCancelButton(boolean);
+  }
+
+}
+
+package android.support.v7.appcompat {
+
+  public final class R {
+    ctor public R();
+  }
+
+  public static final class R.anim {
+    ctor public R.anim();
+    field public static int abc_fade_in;
+    field public static int abc_fade_out;
+    field public static int abc_grow_fade_in_from_bottom;
+    field public static int abc_popup_enter;
+    field public static int abc_popup_exit;
+    field public static int abc_shrink_fade_out_from_bottom;
+    field public static int abc_slide_in_bottom;
+    field public static int abc_slide_in_top;
+    field public static int abc_slide_out_bottom;
+    field public static int abc_slide_out_top;
+  }
+
+  public static final class R.attr {
+    ctor public R.attr();
+    field public static int actionBarDivider;
+    field public static int actionBarItemBackground;
+    field public static int actionBarPopupTheme;
+    field public static int actionBarSize;
+    field public static int actionBarSplitStyle;
+    field public static int actionBarStyle;
+    field public static int actionBarTabBarStyle;
+    field public static int actionBarTabStyle;
+    field public static int actionBarTabTextStyle;
+    field public static int actionBarTheme;
+    field public static int actionBarWidgetTheme;
+    field public static int actionButtonStyle;
+    field public static int actionDropDownStyle;
+    field public static int actionLayout;
+    field public static int actionMenuTextAppearance;
+    field public static int actionMenuTextColor;
+    field public static int actionModeBackground;
+    field public static int actionModeCloseButtonStyle;
+    field public static int actionModeCloseDrawable;
+    field public static int actionModeCopyDrawable;
+    field public static int actionModeCutDrawable;
+    field public static int actionModeFindDrawable;
+    field public static int actionModePasteDrawable;
+    field public static int actionModePopupWindowStyle;
+    field public static int actionModeSelectAllDrawable;
+    field public static int actionModeShareDrawable;
+    field public static int actionModeSplitBackground;
+    field public static int actionModeStyle;
+    field public static int actionModeWebSearchDrawable;
+    field public static int actionOverflowButtonStyle;
+    field public static int actionOverflowMenuStyle;
+    field public static int actionProviderClass;
+    field public static int actionViewClass;
+    field public static int activityChooserViewStyle;
+    field public static int alertDialogButtonGroupStyle;
+    field public static int alertDialogCenterButtons;
+    field public static int alertDialogStyle;
+    field public static int alertDialogTheme;
+    field public static int allowStacking;
+    field public static int arrowHeadLength;
+    field public static int arrowShaftLength;
+    field public static int autoCompleteTextViewStyle;
+    field public static int background;
+    field public static int backgroundSplit;
+    field public static int backgroundStacked;
+    field public static int backgroundTint;
+    field public static int backgroundTintMode;
+    field public static int barLength;
+    field public static int borderlessButtonStyle;
+    field public static int buttonBarButtonStyle;
+    field public static int buttonBarNegativeButtonStyle;
+    field public static int buttonBarNeutralButtonStyle;
+    field public static int buttonBarPositiveButtonStyle;
+    field public static int buttonBarStyle;
+    field public static int buttonPanelSideLayout;
+    field public static int buttonStyle;
+    field public static int buttonStyleSmall;
+    field public static int buttonTint;
+    field public static int buttonTintMode;
+    field public static int checkboxStyle;
+    field public static int checkedTextViewStyle;
+    field public static int closeIcon;
+    field public static int closeItemLayout;
+    field public static int collapseContentDescription;
+    field public static int collapseIcon;
+    field public static int color;
+    field public static int colorAccent;
+    field public static int colorButtonNormal;
+    field public static int colorControlActivated;
+    field public static int colorControlHighlight;
+    field public static int colorControlNormal;
+    field public static int colorPrimary;
+    field public static int colorPrimaryDark;
+    field public static int colorSwitchThumbNormal;
+    field public static int commitIcon;
+    field public static int contentInsetEnd;
+    field public static int contentInsetLeft;
+    field public static int contentInsetRight;
+    field public static int contentInsetStart;
+    field public static int controlBackground;
+    field public static int customNavigationLayout;
+    field public static int defaultQueryHint;
+    field public static int dialogPreferredPadding;
+    field public static int dialogTheme;
+    field public static int displayOptions;
+    field public static int divider;
+    field public static int dividerHorizontal;
+    field public static int dividerPadding;
+    field public static int dividerVertical;
+    field public static int drawableSize;
+    field public static int drawerArrowStyle;
+    field public static int dropDownListViewStyle;
+    field public static int dropdownListPreferredItemHeight;
+    field public static int editTextBackground;
+    field public static int editTextColor;
+    field public static int editTextStyle;
+    field public static int elevation;
+    field public static int expandActivityOverflowButtonDrawable;
+    field public static int gapBetweenBars;
+    field public static int goIcon;
+    field public static int height;
+    field public static int hideOnContentScroll;
+    field public static int homeAsUpIndicator;
+    field public static int homeLayout;
+    field public static int icon;
+    field public static int iconifiedByDefault;
+    field public static int imageButtonStyle;
+    field public static int indeterminateProgressStyle;
+    field public static int initialActivityCount;
+    field public static int isLightTheme;
+    field public static int itemPadding;
+    field public static int layout;
+    field public static int listChoiceBackgroundIndicator;
+    field public static int listDividerAlertDialog;
+    field public static int listItemLayout;
+    field public static int listLayout;
+    field public static int listPopupWindowStyle;
+    field public static int listPreferredItemHeight;
+    field public static int listPreferredItemHeightLarge;
+    field public static int listPreferredItemHeightSmall;
+    field public static int listPreferredItemPaddingLeft;
+    field public static int listPreferredItemPaddingRight;
+    field public static int logo;
+    field public static int logoDescription;
+    field public static int maxButtonHeight;
+    field public static int measureWithLargestChild;
+    field public static int multiChoiceItemLayout;
+    field public static int navigationContentDescription;
+    field public static int navigationIcon;
+    field public static int navigationMode;
+    field public static int overlapAnchor;
+    field public static int paddingEnd;
+    field public static int paddingStart;
+    field public static int panelBackground;
+    field public static int panelMenuListTheme;
+    field public static int panelMenuListWidth;
+    field public static int popupMenuStyle;
+    field public static int popupTheme;
+    field public static int popupWindowStyle;
+    field public static int preserveIconSpacing;
+    field public static int progressBarPadding;
+    field public static int progressBarStyle;
+    field public static int queryBackground;
+    field public static int queryHint;
+    field public static int radioButtonStyle;
+    field public static int ratingBarStyle;
+    field public static int searchHintIcon;
+    field public static int searchIcon;
+    field public static int searchViewStyle;
+    field public static int seekBarStyle;
+    field public static int selectableItemBackground;
+    field public static int selectableItemBackgroundBorderless;
+    field public static int showAsAction;
+    field public static int showDividers;
+    field public static int showText;
+    field public static int singleChoiceItemLayout;
+    field public static int spinBars;
+    field public static int spinnerDropDownItemStyle;
+    field public static int spinnerStyle;
+    field public static int splitTrack;
+    field public static int state_above_anchor;
+    field public static int submitBackground;
+    field public static int subtitle;
+    field public static int subtitleTextAppearance;
+    field public static int subtitleTextColor;
+    field public static int subtitleTextStyle;
+    field public static int suggestionRowLayout;
+    field public static int switchMinWidth;
+    field public static int switchPadding;
+    field public static int switchStyle;
+    field public static int switchTextAppearance;
+    field public static int textAllCaps;
+    field public static int textAppearanceLargePopupMenu;
+    field public static int textAppearanceListItem;
+    field public static int textAppearanceListItemSmall;
+    field public static int textAppearanceSearchResultSubtitle;
+    field public static int textAppearanceSearchResultTitle;
+    field public static int textAppearanceSmallPopupMenu;
+    field public static int textColorAlertDialogListItem;
+    field public static int textColorSearchUrl;
+    field public static int theme;
+    field public static int thickness;
+    field public static int thumbTextPadding;
+    field public static int title;
+    field public static int titleMarginBottom;
+    field public static int titleMarginEnd;
+    field public static int titleMarginStart;
+    field public static int titleMarginTop;
+    field public static int titleMargins;
+    field public static int titleTextAppearance;
+    field public static int titleTextColor;
+    field public static int titleTextStyle;
+    field public static int toolbarNavigationButtonStyle;
+    field public static int toolbarStyle;
+    field public static int track;
+    field public static int voiceIcon;
+    field public static int windowActionBar;
+    field public static int windowActionBarOverlay;
+    field public static int windowActionModeOverlay;
+    field public static int windowFixedHeightMajor;
+    field public static int windowFixedHeightMinor;
+    field public static int windowFixedWidthMajor;
+    field public static int windowFixedWidthMinor;
+    field public static int windowMinWidthMajor;
+    field public static int windowMinWidthMinor;
+    field public static int windowNoTitle;
+  }
+
+  public static final class R.bool {
+    ctor public R.bool();
+    field public static int abc_action_bar_embed_tabs;
+    field public static int abc_action_bar_embed_tabs_pre_jb;
+    field public static int abc_action_bar_expanded_action_views_exclusive;
+    field public static int abc_allow_stacked_button_bar;
+    field public static int abc_config_actionMenuItemAllCaps;
+    field public static int abc_config_allowActionMenuItemTextWithIcon;
+    field public static int abc_config_closeDialogWhenTouchOutside;
+    field public static int abc_config_showMenuShortcutsWhenKeyboardPresent;
+  }
+
+  public static final class R.color {
+    ctor public R.color();
+    field public static int abc_background_cache_hint_selector_material_dark;
+    field public static int abc_background_cache_hint_selector_material_light;
+    field public static int abc_color_highlight_material;
+    field public static int abc_input_method_navigation_guard;
+    field public static int abc_primary_text_disable_only_material_dark;
+    field public static int abc_primary_text_disable_only_material_light;
+    field public static int abc_primary_text_material_dark;
+    field public static int abc_primary_text_material_light;
+    field public static int abc_search_url_text;
+    field public static int abc_search_url_text_normal;
+    field public static int abc_search_url_text_pressed;
+    field public static int abc_search_url_text_selected;
+    field public static int abc_secondary_text_material_dark;
+    field public static int abc_secondary_text_material_light;
+    field public static int accent_material_dark;
+    field public static int accent_material_light;
+    field public static int background_floating_material_dark;
+    field public static int background_floating_material_light;
+    field public static int background_material_dark;
+    field public static int background_material_light;
+    field public static int bright_foreground_disabled_material_dark;
+    field public static int bright_foreground_disabled_material_light;
+    field public static int bright_foreground_inverse_material_dark;
+    field public static int bright_foreground_inverse_material_light;
+    field public static int bright_foreground_material_dark;
+    field public static int bright_foreground_material_light;
+    field public static int button_material_dark;
+    field public static int button_material_light;
+    field public static int dim_foreground_disabled_material_dark;
+    field public static int dim_foreground_disabled_material_light;
+    field public static int dim_foreground_material_dark;
+    field public static int dim_foreground_material_light;
+    field public static int foreground_material_dark;
+    field public static int foreground_material_light;
+    field public static int highlighted_text_material_dark;
+    field public static int highlighted_text_material_light;
+    field public static int hint_foreground_material_dark;
+    field public static int hint_foreground_material_light;
+    field public static int material_blue_grey_800;
+    field public static int material_blue_grey_900;
+    field public static int material_blue_grey_950;
+    field public static int material_deep_teal_200;
+    field public static int material_deep_teal_500;
+    field public static int material_grey_100;
+    field public static int material_grey_300;
+    field public static int material_grey_50;
+    field public static int material_grey_600;
+    field public static int material_grey_800;
+    field public static int material_grey_850;
+    field public static int material_grey_900;
+    field public static int primary_dark_material_dark;
+    field public static int primary_dark_material_light;
+    field public static int primary_material_dark;
+    field public static int primary_material_light;
+    field public static int primary_text_default_material_dark;
+    field public static int primary_text_default_material_light;
+    field public static int primary_text_disabled_material_dark;
+    field public static int primary_text_disabled_material_light;
+    field public static int ripple_material_dark;
+    field public static int ripple_material_light;
+    field public static int secondary_text_default_material_dark;
+    field public static int secondary_text_default_material_light;
+    field public static int secondary_text_disabled_material_dark;
+    field public static int secondary_text_disabled_material_light;
+    field public static int switch_thumb_disabled_material_dark;
+    field public static int switch_thumb_disabled_material_light;
+    field public static int switch_thumb_material_dark;
+    field public static int switch_thumb_material_light;
+    field public static int switch_thumb_normal_material_dark;
+    field public static int switch_thumb_normal_material_light;
+  }
+
+  public static final class R.dimen {
+    ctor public R.dimen();
+    field public static int abc_action_bar_content_inset_material;
+    field public static int abc_action_bar_default_height_material;
+    field public static int abc_action_bar_default_padding_end_material;
+    field public static int abc_action_bar_default_padding_start_material;
+    field public static int abc_action_bar_icon_vertical_padding_material;
+    field public static int abc_action_bar_overflow_padding_end_material;
+    field public static int abc_action_bar_overflow_padding_start_material;
+    field public static int abc_action_bar_progress_bar_size;
+    field public static int abc_action_bar_stacked_max_height;
+    field public static int abc_action_bar_stacked_tab_max_width;
+    field public static int abc_action_bar_subtitle_bottom_margin_material;
+    field public static int abc_action_bar_subtitle_top_margin_material;
+    field public static int abc_action_button_min_height_material;
+    field public static int abc_action_button_min_width_material;
+    field public static int abc_action_button_min_width_overflow_material;
+    field public static int abc_alert_dialog_button_bar_height;
+    field public static int abc_button_inset_horizontal_material;
+    field public static int abc_button_inset_vertical_material;
+    field public static int abc_button_padding_horizontal_material;
+    field public static int abc_button_padding_vertical_material;
+    field public static int abc_config_prefDialogWidth;
+    field public static int abc_control_corner_material;
+    field public static int abc_control_inset_material;
+    field public static int abc_control_padding_material;
+    field public static int abc_dialog_fixed_height_major;
+    field public static int abc_dialog_fixed_height_minor;
+    field public static int abc_dialog_fixed_width_major;
+    field public static int abc_dialog_fixed_width_minor;
+    field public static int abc_dialog_list_padding_vertical_material;
+    field public static int abc_dialog_min_width_major;
+    field public static int abc_dialog_min_width_minor;
+    field public static int abc_dialog_padding_material;
+    field public static int abc_dialog_padding_top_material;
+    field public static int abc_disabled_alpha_material_dark;
+    field public static int abc_disabled_alpha_material_light;
+    field public static int abc_dropdownitem_icon_width;
+    field public static int abc_dropdownitem_text_padding_left;
+    field public static int abc_dropdownitem_text_padding_right;
+    field public static int abc_edit_text_inset_bottom_material;
+    field public static int abc_edit_text_inset_horizontal_material;
+    field public static int abc_edit_text_inset_top_material;
+    field public static int abc_floating_window_z;
+    field public static int abc_list_item_padding_horizontal_material;
+    field public static int abc_panel_menu_list_width;
+    field public static int abc_search_view_preferred_width;
+    field public static int abc_search_view_text_min_width;
+    field public static int abc_seekbar_track_background_height_material;
+    field public static int abc_seekbar_track_progress_height_material;
+    field public static int abc_select_dialog_padding_start_material;
+    field public static int abc_switch_padding;
+    field public static int abc_text_size_body_1_material;
+    field public static int abc_text_size_body_2_material;
+    field public static int abc_text_size_button_material;
+    field public static int abc_text_size_caption_material;
+    field public static int abc_text_size_display_1_material;
+    field public static int abc_text_size_display_2_material;
+    field public static int abc_text_size_display_3_material;
+    field public static int abc_text_size_display_4_material;
+    field public static int abc_text_size_headline_material;
+    field public static int abc_text_size_large_material;
+    field public static int abc_text_size_medium_material;
+    field public static int abc_text_size_menu_material;
+    field public static int abc_text_size_small_material;
+    field public static int abc_text_size_subhead_material;
+    field public static int abc_text_size_subtitle_material_toolbar;
+    field public static int abc_text_size_title_material;
+    field public static int abc_text_size_title_material_toolbar;
+    field public static int disabled_alpha_material_dark;
+    field public static int disabled_alpha_material_light;
+    field public static int highlight_alpha_material_colored;
+    field public static int highlight_alpha_material_dark;
+    field public static int highlight_alpha_material_light;
+    field public static int notification_large_icon_height;
+    field public static int notification_large_icon_width;
+    field public static int notification_subtext_size;
+  }
+
+  public static final class R.drawable {
+    ctor public R.drawable();
+    field public static int abc_ab_share_pack_mtrl_alpha;
+    field public static int abc_action_bar_item_background_material;
+    field public static int abc_btn_borderless_material;
+    field public static int abc_btn_check_material;
+    field public static int abc_btn_check_to_on_mtrl_000;
+    field public static int abc_btn_check_to_on_mtrl_015;
+    field public static int abc_btn_colored_material;
+    field public static int abc_btn_default_material;
+    field public static int abc_btn_default_mtrl_shape;
+    field public static int abc_btn_radio_material;
+    field public static int abc_btn_radio_to_on_mtrl_000;
+    field public static int abc_btn_radio_to_on_mtrl_015;
+    field public static int abc_btn_rating_star_off_mtrl_alpha;
+    field public static int abc_btn_rating_star_on_mtrl_alpha;
+    field public static int abc_btn_switch_to_on_mtrl_00001;
+    field public static int abc_btn_switch_to_on_mtrl_00012;
+    field public static int abc_cab_background_internal_bg;
+    field public static int abc_cab_background_top_material;
+    field public static int abc_cab_background_top_mtrl_alpha;
+    field public static int abc_control_background_material;
+    field public static int abc_dialog_material_background_dark;
+    field public static int abc_dialog_material_background_light;
+    field public static int abc_edit_text_material;
+    field public static int abc_ic_ab_back_mtrl_am_alpha;
+    field public static int abc_ic_clear_mtrl_alpha;
+    field public static int abc_ic_commit_search_api_mtrl_alpha;
+    field public static int abc_ic_go_search_api_mtrl_alpha;
+    field public static int abc_ic_menu_copy_mtrl_am_alpha;
+    field public static int abc_ic_menu_cut_mtrl_alpha;
+    field public static int abc_ic_menu_moreoverflow_mtrl_alpha;
+    field public static int abc_ic_menu_paste_mtrl_am_alpha;
+    field public static int abc_ic_menu_selectall_mtrl_alpha;
+    field public static int abc_ic_menu_share_mtrl_alpha;
+    field public static int abc_ic_search_api_mtrl_alpha;
+    field public static int abc_ic_voice_search_api_mtrl_alpha;
+    field public static int abc_item_background_holo_dark;
+    field public static int abc_item_background_holo_light;
+    field public static int abc_list_divider_mtrl_alpha;
+    field public static int abc_list_focused_holo;
+    field public static int abc_list_longpressed_holo;
+    field public static int abc_list_pressed_holo_dark;
+    field public static int abc_list_pressed_holo_light;
+    field public static int abc_list_selector_background_transition_holo_dark;
+    field public static int abc_list_selector_background_transition_holo_light;
+    field public static int abc_list_selector_disabled_holo_dark;
+    field public static int abc_list_selector_disabled_holo_light;
+    field public static int abc_list_selector_holo_dark;
+    field public static int abc_list_selector_holo_light;
+    field public static int abc_menu_hardkey_panel_mtrl_mult;
+    field public static int abc_popup_background_mtrl_mult;
+    field public static int abc_ratingbar_full_material;
+    field public static int abc_scrubber_control_off_mtrl_alpha;
+    field public static int abc_scrubber_control_to_pressed_mtrl_000;
+    field public static int abc_scrubber_control_to_pressed_mtrl_005;
+    field public static int abc_scrubber_primary_mtrl_alpha;
+    field public static int abc_scrubber_track_mtrl_alpha;
+    field public static int abc_seekbar_thumb_material;
+    field public static int abc_seekbar_track_material;
+    field public static int abc_spinner_mtrl_am_alpha;
+    field public static int abc_spinner_textfield_background_material;
+    field public static int abc_switch_thumb_material;
+    field public static int abc_switch_track_mtrl_alpha;
+    field public static int abc_tab_indicator_material;
+    field public static int abc_tab_indicator_mtrl_alpha;
+    field public static int abc_text_cursor_material;
+    field public static int abc_textfield_activated_mtrl_alpha;
+    field public static int abc_textfield_default_mtrl_alpha;
+    field public static int abc_textfield_search_activated_mtrl_alpha;
+    field public static int abc_textfield_search_default_mtrl_alpha;
+    field public static int abc_textfield_search_material;
+    field public static int notification_template_icon_bg;
+  }
+
+  public static final class R.id {
+    ctor public R.id();
+    field public static int action0;
+    field public static int action_bar;
+    field public static int action_bar_activity_content;
+    field public static int action_bar_container;
+    field public static int action_bar_root;
+    field public static int action_bar_spinner;
+    field public static int action_bar_subtitle;
+    field public static int action_bar_title;
+    field public static int action_context_bar;
+    field public static int action_divider;
+    field public static int action_menu_divider;
+    field public static int action_menu_presenter;
+    field public static int action_mode_bar;
+    field public static int action_mode_bar_stub;
+    field public static int action_mode_close_button;
+    field public static int activity_chooser_view_content;
+    field public static int alertTitle;
+    field public static int always;
+    field public static int beginning;
+    field public static int buttonPanel;
+    field public static int cancel_action;
+    field public static int checkbox;
+    field public static int chronometer;
+    field public static int collapseActionView;
+    field public static int contentPanel;
+    field public static int custom;
+    field public static int customPanel;
+    field public static int decor_content_parent;
+    field public static int default_activity_button;
+    field public static int disableHome;
+    field public static int edit_query;
+    field public static int end;
+    field public static int end_padder;
+    field public static int expand_activities_button;
+    field public static int expanded_menu;
+    field public static int home;
+    field public static int homeAsUp;
+    field public static int icon;
+    field public static int ifRoom;
+    field public static int image;
+    field public static int info;
+    field public static int line1;
+    field public static int line3;
+    field public static int listMode;
+    field public static int list_item;
+    field public static int media_actions;
+    field public static int middle;
+    field public static int multiply;
+    field public static int never;
+    field public static int none;
+    field public static int normal;
+    field public static int parentPanel;
+    field public static int progress_circular;
+    field public static int progress_horizontal;
+    field public static int radio;
+    field public static int screen;
+    field public static int scrollIndicatorDown;
+    field public static int scrollIndicatorUp;
+    field public static int scrollView;
+    field public static int search_badge;
+    field public static int search_bar;
+    field public static int search_button;
+    field public static int search_close_btn;
+    field public static int search_edit_frame;
+    field public static int search_go_btn;
+    field public static int search_mag_icon;
+    field public static int search_plate;
+    field public static int search_src_text;
+    field public static int search_voice_btn;
+    field public static int select_dialog_listview;
+    field public static int shortcut;
+    field public static int showCustom;
+    field public static int showHome;
+    field public static int showTitle;
+    field public static int spacer;
+    field public static int split_action_bar;
+    field public static int src_atop;
+    field public static int src_in;
+    field public static int src_over;
+    field public static int status_bar_latest_event_content;
+    field public static int submit_area;
+    field public static int tabMode;
+    field public static int text;
+    field public static int text2;
+    field public static int textSpacerNoButtons;
+    field public static int time;
+    field public static int title;
+    field public static int title_template;
+    field public static int topPanel;
+    field public static int up;
+    field public static int useLogo;
+    field public static int withText;
+    field public static int wrap_content;
+  }
+
+  public static final class R.integer {
+    ctor public R.integer();
+    field public static int abc_config_activityDefaultDur;
+    field public static int abc_config_activityShortDur;
+    field public static int abc_max_action_buttons;
+    field public static int cancel_button_image_alpha;
+    field public static int status_bar_notification_info_maxnum;
+  }
+
+  public static final class R.layout {
+    ctor public R.layout();
+    field public static int abc_action_bar_title_item;
+    field public static int abc_action_bar_up_container;
+    field public static int abc_action_bar_view_list_nav_layout;
+    field public static int abc_action_menu_item_layout;
+    field public static int abc_action_menu_layout;
+    field public static int abc_action_mode_bar;
+    field public static int abc_action_mode_close_item_material;
+    field public static int abc_activity_chooser_view;
+    field public static int abc_activity_chooser_view_list_item;
+    field public static int abc_alert_dialog_button_bar_material;
+    field public static int abc_alert_dialog_material;
+    field public static int abc_dialog_title_material;
+    field public static int abc_expanded_menu_layout;
+    field public static int abc_list_menu_item_checkbox;
+    field public static int abc_list_menu_item_icon;
+    field public static int abc_list_menu_item_layout;
+    field public static int abc_list_menu_item_radio;
+    field public static int abc_popup_menu_item_layout;
+    field public static int abc_screen_content_include;
+    field public static int abc_screen_simple;
+    field public static int abc_screen_simple_overlay_action_mode;
+    field public static int abc_screen_toolbar;
+    field public static int abc_search_dropdown_item_icons_2line;
+    field public static int abc_search_view;
+    field public static int abc_select_dialog_material;
+    field public static int notification_media_action;
+    field public static int notification_media_cancel_action;
+    field public static int notification_template_big_media;
+    field public static int notification_template_big_media_narrow;
+    field public static int notification_template_lines;
+    field public static int notification_template_media;
+    field public static int notification_template_part_chronometer;
+    field public static int notification_template_part_time;
+    field public static int select_dialog_item_material;
+    field public static int select_dialog_multichoice_material;
+    field public static int select_dialog_singlechoice_material;
+    field public static int support_simple_spinner_dropdown_item;
+  }
+
+  public static final class R.string {
+    ctor public R.string();
+    field public static int abc_action_bar_home_description;
+    field public static int abc_action_bar_home_description_format;
+    field public static int abc_action_bar_home_subtitle_description_format;
+    field public static int abc_action_bar_up_description;
+    field public static int abc_action_menu_overflow_description;
+    field public static int abc_action_mode_done;
+    field public static int abc_activity_chooser_view_see_all;
+    field public static int abc_activitychooserview_choose_application;
+    field public static int abc_capital_off;
+    field public static int abc_capital_on;
+    field public static int abc_search_hint;
+    field public static int abc_searchview_description_clear;
+    field public static int abc_searchview_description_query;
+    field public static int abc_searchview_description_search;
+    field public static int abc_searchview_description_submit;
+    field public static int abc_searchview_description_voice;
+    field public static int abc_shareactionprovider_share_with;
+    field public static int abc_shareactionprovider_share_with_application;
+    field public static int abc_toolbar_collapse_description;
+    field public static int status_bar_notification_info_overflow;
+  }
+
+  public static final class R.style {
+    ctor public R.style();
+    field public static int AlertDialog_AppCompat;
+    field public static int AlertDialog_AppCompat_Light;
+    field public static int Animation_AppCompat_Dialog;
+    field public static int Animation_AppCompat_DropDownUp;
+    field public static int Base_AlertDialog_AppCompat;
+    field public static int Base_AlertDialog_AppCompat_Light;
+    field public static int Base_Animation_AppCompat_Dialog;
+    field public static int Base_Animation_AppCompat_DropDownUp;
+    field public static int Base_DialogWindowTitleBackground_AppCompat;
+    field public static int Base_DialogWindowTitle_AppCompat;
+    field public static int Base_TextAppearance_AppCompat;
+    field public static int Base_TextAppearance_AppCompat_Body1;
+    field public static int Base_TextAppearance_AppCompat_Body2;
+    field public static int Base_TextAppearance_AppCompat_Button;
+    field public static int Base_TextAppearance_AppCompat_Caption;
+    field public static int Base_TextAppearance_AppCompat_Display1;
+    field public static int Base_TextAppearance_AppCompat_Display2;
+    field public static int Base_TextAppearance_AppCompat_Display3;
+    field public static int Base_TextAppearance_AppCompat_Display4;
+    field public static int Base_TextAppearance_AppCompat_Headline;
+    field public static int Base_TextAppearance_AppCompat_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Large;
+    field public static int Base_TextAppearance_AppCompat_Large_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Large;
+    field public static int Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Small;
+    field public static int Base_TextAppearance_AppCompat_Medium;
+    field public static int Base_TextAppearance_AppCompat_Medium_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Menu;
+    field public static int Base_TextAppearance_AppCompat_SearchResult;
+    field public static int Base_TextAppearance_AppCompat_SearchResult_Subtitle;
+    field public static int Base_TextAppearance_AppCompat_SearchResult_Title;
+    field public static int Base_TextAppearance_AppCompat_Small;
+    field public static int Base_TextAppearance_AppCompat_Small_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Subhead;
+    field public static int Base_TextAppearance_AppCompat_Subhead_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Title;
+    field public static int Base_TextAppearance_AppCompat_Title_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Menu;
+    field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle;
+    field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Title;
+    field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Widget_ActionMode_Subtitle;
+    field public static int Base_TextAppearance_AppCompat_Widget_ActionMode_Title;
+    field public static int Base_TextAppearance_AppCompat_Widget_Button;
+    field public static int Base_TextAppearance_AppCompat_Widget_Button_Inverse;
+    field public static int Base_TextAppearance_AppCompat_Widget_DropDownItem;
+    field public static int Base_TextAppearance_AppCompat_Widget_PopupMenu_Large;
+    field public static int Base_TextAppearance_AppCompat_Widget_PopupMenu_Small;
+    field public static int Base_TextAppearance_AppCompat_Widget_Switch;
+    field public static int Base_TextAppearance_AppCompat_Widget_TextView_SpinnerItem;
+    field public static int Base_TextAppearance_Widget_AppCompat_ExpandedMenu_Item;
+    field public static int Base_TextAppearance_Widget_AppCompat_Toolbar_Subtitle;
+    field public static int Base_TextAppearance_Widget_AppCompat_Toolbar_Title;
+    field public static int Base_ThemeOverlay_AppCompat;
+    field public static int Base_ThemeOverlay_AppCompat_ActionBar;
+    field public static int Base_ThemeOverlay_AppCompat_Dark;
+    field public static int Base_ThemeOverlay_AppCompat_Dark_ActionBar;
+    field public static int Base_ThemeOverlay_AppCompat_Light;
+    field public static int Base_Theme_AppCompat;
+    field public static int Base_Theme_AppCompat_CompactMenu;
+    field public static int Base_Theme_AppCompat_Dialog;
+    field public static int Base_Theme_AppCompat_DialogWhenLarge;
+    field public static int Base_Theme_AppCompat_Dialog_Alert;
+    field public static int Base_Theme_AppCompat_Dialog_FixedSize;
+    field public static int Base_Theme_AppCompat_Dialog_MinWidth;
+    field public static int Base_Theme_AppCompat_Light;
+    field public static int Base_Theme_AppCompat_Light_DarkActionBar;
+    field public static int Base_Theme_AppCompat_Light_Dialog;
+    field public static int Base_Theme_AppCompat_Light_DialogWhenLarge;
+    field public static int Base_Theme_AppCompat_Light_Dialog_Alert;
+    field public static int Base_Theme_AppCompat_Light_Dialog_FixedSize;
+    field public static int Base_Theme_AppCompat_Light_Dialog_MinWidth;
+    field public static int Base_V11_Theme_AppCompat_Dialog;
+    field public static int Base_V11_Theme_AppCompat_Light_Dialog;
+    field public static int Base_V12_Widget_AppCompat_AutoCompleteTextView;
+    field public static int Base_V12_Widget_AppCompat_EditText;
+    field public static int Base_V21_Theme_AppCompat;
+    field public static int Base_V21_Theme_AppCompat_Dialog;
+    field public static int Base_V21_Theme_AppCompat_Light;
+    field public static int Base_V21_Theme_AppCompat_Light_Dialog;
+    field public static int Base_V22_Theme_AppCompat;
+    field public static int Base_V22_Theme_AppCompat_Light;
+    field public static int Base_V23_Theme_AppCompat;
+    field public static int Base_V23_Theme_AppCompat_Light;
+    field public static int Base_V7_Theme_AppCompat;
+    field public static int Base_V7_Theme_AppCompat_Dialog;
+    field public static int Base_V7_Theme_AppCompat_Light;
+    field public static int Base_V7_Theme_AppCompat_Light_Dialog;
+    field public static int Base_V7_Widget_AppCompat_AutoCompleteTextView;
+    field public static int Base_V7_Widget_AppCompat_EditText;
+    field public static int Base_Widget_AppCompat_ActionBar;
+    field public static int Base_Widget_AppCompat_ActionBar_Solid;
+    field public static int Base_Widget_AppCompat_ActionBar_TabBar;
+    field public static int Base_Widget_AppCompat_ActionBar_TabText;
+    field public static int Base_Widget_AppCompat_ActionBar_TabView;
+    field public static int Base_Widget_AppCompat_ActionButton;
+    field public static int Base_Widget_AppCompat_ActionButton_CloseMode;
+    field public static int Base_Widget_AppCompat_ActionButton_Overflow;
+    field public static int Base_Widget_AppCompat_ActionMode;
+    field public static int Base_Widget_AppCompat_ActivityChooserView;
+    field public static int Base_Widget_AppCompat_AutoCompleteTextView;
+    field public static int Base_Widget_AppCompat_Button;
+    field public static int Base_Widget_AppCompat_ButtonBar;
+    field public static int Base_Widget_AppCompat_ButtonBar_AlertDialog;
+    field public static int Base_Widget_AppCompat_Button_Borderless;
+    field public static int Base_Widget_AppCompat_Button_Borderless_Colored;
+    field public static int Base_Widget_AppCompat_Button_ButtonBar_AlertDialog;
+    field public static int Base_Widget_AppCompat_Button_Colored;
+    field public static int Base_Widget_AppCompat_Button_Small;
+    field public static int Base_Widget_AppCompat_CompoundButton_CheckBox;
+    field public static int Base_Widget_AppCompat_CompoundButton_RadioButton;
+    field public static int Base_Widget_AppCompat_CompoundButton_Switch;
+    field public static int Base_Widget_AppCompat_DrawerArrowToggle;
+    field public static int Base_Widget_AppCompat_DrawerArrowToggle_Common;
+    field public static int Base_Widget_AppCompat_DropDownItem_Spinner;
+    field public static int Base_Widget_AppCompat_EditText;
+    field public static int Base_Widget_AppCompat_ImageButton;
+    field public static int Base_Widget_AppCompat_Light_ActionBar;
+    field public static int Base_Widget_AppCompat_Light_ActionBar_Solid;
+    field public static int Base_Widget_AppCompat_Light_ActionBar_TabBar;
+    field public static int Base_Widget_AppCompat_Light_ActionBar_TabText;
+    field public static int Base_Widget_AppCompat_Light_ActionBar_TabText_Inverse;
+    field public static int Base_Widget_AppCompat_Light_ActionBar_TabView;
+    field public static int Base_Widget_AppCompat_Light_PopupMenu;
+    field public static int Base_Widget_AppCompat_Light_PopupMenu_Overflow;
+    field public static int Base_Widget_AppCompat_ListPopupWindow;
+    field public static int Base_Widget_AppCompat_ListView;
+    field public static int Base_Widget_AppCompat_ListView_DropDown;
+    field public static int Base_Widget_AppCompat_ListView_Menu;
+    field public static int Base_Widget_AppCompat_PopupMenu;
+    field public static int Base_Widget_AppCompat_PopupMenu_Overflow;
+    field public static int Base_Widget_AppCompat_PopupWindow;
+    field public static int Base_Widget_AppCompat_ProgressBar;
+    field public static int Base_Widget_AppCompat_ProgressBar_Horizontal;
+    field public static int Base_Widget_AppCompat_RatingBar;
+    field public static int Base_Widget_AppCompat_SearchView;
+    field public static int Base_Widget_AppCompat_SearchView_ActionBar;
+    field public static int Base_Widget_AppCompat_SeekBar;
+    field public static int Base_Widget_AppCompat_Spinner;
+    field public static int Base_Widget_AppCompat_Spinner_Underlined;
+    field public static int Base_Widget_AppCompat_TextView_SpinnerItem;
+    field public static int Base_Widget_AppCompat_Toolbar;
+    field public static int Base_Widget_AppCompat_Toolbar_Button_Navigation;
+    field public static int Platform_AppCompat;
+    field public static int Platform_AppCompat_Light;
+    field public static int Platform_ThemeOverlay_AppCompat;
+    field public static int Platform_ThemeOverlay_AppCompat_Dark;
+    field public static int Platform_ThemeOverlay_AppCompat_Light;
+    field public static int Platform_V11_AppCompat;
+    field public static int Platform_V11_AppCompat_Light;
+    field public static int Platform_V14_AppCompat;
+    field public static int Platform_V14_AppCompat_Light;
+    field public static int Platform_Widget_AppCompat_Spinner;
+    field public static int RtlOverlay_DialogWindowTitle_AppCompat;
+    field public static int RtlOverlay_Widget_AppCompat_ActionBar_TitleItem;
+    field public static int RtlOverlay_Widget_AppCompat_DialogTitle_Icon;
+    field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem;
+    field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem_InternalGroup;
+    field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem_Text;
+    field public static int RtlOverlay_Widget_AppCompat_SearchView_MagIcon;
+    field public static int RtlOverlay_Widget_AppCompat_Search_DropDown;
+    field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Icon1;
+    field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Icon2;
+    field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Query;
+    field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Text;
+    field public static int RtlUnderlay_Widget_AppCompat_ActionButton;
+    field public static int RtlUnderlay_Widget_AppCompat_ActionButton_Overflow;
+    field public static int TextAppearance_AppCompat;
+    field public static int TextAppearance_AppCompat_Body1;
+    field public static int TextAppearance_AppCompat_Body2;
+    field public static int TextAppearance_AppCompat_Button;
+    field public static int TextAppearance_AppCompat_Caption;
+    field public static int TextAppearance_AppCompat_Display1;
+    field public static int TextAppearance_AppCompat_Display2;
+    field public static int TextAppearance_AppCompat_Display3;
+    field public static int TextAppearance_AppCompat_Display4;
+    field public static int TextAppearance_AppCompat_Headline;
+    field public static int TextAppearance_AppCompat_Inverse;
+    field public static int TextAppearance_AppCompat_Large;
+    field public static int TextAppearance_AppCompat_Large_Inverse;
+    field public static int TextAppearance_AppCompat_Light_SearchResult_Subtitle;
+    field public static int TextAppearance_AppCompat_Light_SearchResult_Title;
+    field public static int TextAppearance_AppCompat_Light_Widget_PopupMenu_Large;
+    field public static int TextAppearance_AppCompat_Light_Widget_PopupMenu_Small;
+    field public static int TextAppearance_AppCompat_Medium;
+    field public static int TextAppearance_AppCompat_Medium_Inverse;
+    field public static int TextAppearance_AppCompat_Menu;
+    field public static int TextAppearance_AppCompat_SearchResult_Subtitle;
+    field public static int TextAppearance_AppCompat_SearchResult_Title;
+    field public static int TextAppearance_AppCompat_Small;
+    field public static int TextAppearance_AppCompat_Small_Inverse;
+    field public static int TextAppearance_AppCompat_Subhead;
+    field public static int TextAppearance_AppCompat_Subhead_Inverse;
+    field public static int TextAppearance_AppCompat_Title;
+    field public static int TextAppearance_AppCompat_Title_Inverse;
+    field public static int TextAppearance_AppCompat_Widget_ActionBar_Menu;
+    field public static int TextAppearance_AppCompat_Widget_ActionBar_Subtitle;
+    field public static int TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse;
+    field public static int TextAppearance_AppCompat_Widget_ActionBar_Title;
+    field public static int TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse;
+    field public static int TextAppearance_AppCompat_Widget_ActionMode_Subtitle;
+    field public static int TextAppearance_AppCompat_Widget_ActionMode_Subtitle_Inverse;
+    field public static int TextAppearance_AppCompat_Widget_ActionMode_Title;
+    field public static int TextAppearance_AppCompat_Widget_ActionMode_Title_Inverse;
+    field public static int TextAppearance_AppCompat_Widget_Button;
+    field public static int TextAppearance_AppCompat_Widget_Button_Inverse;
+    field public static int TextAppearance_AppCompat_Widget_DropDownItem;
+    field public static int TextAppearance_AppCompat_Widget_PopupMenu_Large;
+    field public static int TextAppearance_AppCompat_Widget_PopupMenu_Small;
+    field public static int TextAppearance_AppCompat_Widget_Switch;
+    field public static int TextAppearance_AppCompat_Widget_TextView_SpinnerItem;
+    field public static int TextAppearance_StatusBar_EventContent;
+    field public static int TextAppearance_StatusBar_EventContent_Info;
+    field public static int TextAppearance_StatusBar_EventContent_Line2;
+    field public static int TextAppearance_StatusBar_EventContent_Time;
+    field public static int TextAppearance_StatusBar_EventContent_Title;
+    field public static int TextAppearance_Widget_AppCompat_ExpandedMenu_Item;
+    field public static int TextAppearance_Widget_AppCompat_Toolbar_Subtitle;
+    field public static int TextAppearance_Widget_AppCompat_Toolbar_Title;
+    field public static int ThemeOverlay_AppCompat;
+    field public static int ThemeOverlay_AppCompat_ActionBar;
+    field public static int ThemeOverlay_AppCompat_Dark;
+    field public static int ThemeOverlay_AppCompat_Dark_ActionBar;
+    field public static int ThemeOverlay_AppCompat_Light;
+    field public static int Theme_AppCompat;
+    field public static int Theme_AppCompat_CompactMenu;
+    field public static int Theme_AppCompat_Dialog;
+    field public static int Theme_AppCompat_DialogWhenLarge;
+    field public static int Theme_AppCompat_Dialog_Alert;
+    field public static int Theme_AppCompat_Dialog_MinWidth;
+    field public static int Theme_AppCompat_Light;
+    field public static int Theme_AppCompat_Light_DarkActionBar;
+    field public static int Theme_AppCompat_Light_Dialog;
+    field public static int Theme_AppCompat_Light_DialogWhenLarge;
+    field public static int Theme_AppCompat_Light_Dialog_Alert;
+    field public static int Theme_AppCompat_Light_Dialog_MinWidth;
+    field public static int Theme_AppCompat_Light_NoActionBar;
+    field public static int Theme_AppCompat_NoActionBar;
+    field public static int Widget_AppCompat_ActionBar;
+    field public static int Widget_AppCompat_ActionBar_Solid;
+    field public static int Widget_AppCompat_ActionBar_TabBar;
+    field public static int Widget_AppCompat_ActionBar_TabText;
+    field public static int Widget_AppCompat_ActionBar_TabView;
+    field public static int Widget_AppCompat_ActionButton;
+    field public static int Widget_AppCompat_ActionButton_CloseMode;
+    field public static int Widget_AppCompat_ActionButton_Overflow;
+    field public static int Widget_AppCompat_ActionMode;
+    field public static int Widget_AppCompat_ActivityChooserView;
+    field public static int Widget_AppCompat_AutoCompleteTextView;
+    field public static int Widget_AppCompat_Button;
+    field public static int Widget_AppCompat_ButtonBar;
+    field public static int Widget_AppCompat_ButtonBar_AlertDialog;
+    field public static int Widget_AppCompat_Button_Borderless;
+    field public static int Widget_AppCompat_Button_Borderless_Colored;
+    field public static int Widget_AppCompat_Button_ButtonBar_AlertDialog;
+    field public static int Widget_AppCompat_Button_Colored;
+    field public static int Widget_AppCompat_Button_Small;
+    field public static int Widget_AppCompat_CompoundButton_CheckBox;
+    field public static int Widget_AppCompat_CompoundButton_RadioButton;
+    field public static int Widget_AppCompat_CompoundButton_Switch;
+    field public static int Widget_AppCompat_DrawerArrowToggle;
+    field public static int Widget_AppCompat_DropDownItem_Spinner;
+    field public static int Widget_AppCompat_EditText;
+    field public static int Widget_AppCompat_ImageButton;
+    field public static int Widget_AppCompat_Light_ActionBar;
+    field public static int Widget_AppCompat_Light_ActionBar_Solid;
+    field public static int Widget_AppCompat_Light_ActionBar_Solid_Inverse;
+    field public static int Widget_AppCompat_Light_ActionBar_TabBar;
+    field public static int Widget_AppCompat_Light_ActionBar_TabBar_Inverse;
+    field public static int Widget_AppCompat_Light_ActionBar_TabText;
+    field public static int Widget_AppCompat_Light_ActionBar_TabText_Inverse;
+    field public static int Widget_AppCompat_Light_ActionBar_TabView;
+    field public static int Widget_AppCompat_Light_ActionBar_TabView_Inverse;
+    field public static int Widget_AppCompat_Light_ActionButton;
+    field public static int Widget_AppCompat_Light_ActionButton_CloseMode;
+    field public static int Widget_AppCompat_Light_ActionButton_Overflow;
+    field public static int Widget_AppCompat_Light_ActionMode_Inverse;
+    field public static int Widget_AppCompat_Light_ActivityChooserView;
+    field public static int Widget_AppCompat_Light_AutoCompleteTextView;
+    field public static int Widget_AppCompat_Light_DropDownItem_Spinner;
+    field public static int Widget_AppCompat_Light_ListPopupWindow;
+    field public static int Widget_AppCompat_Light_ListView_DropDown;
+    field public static int Widget_AppCompat_Light_PopupMenu;
+    field public static int Widget_AppCompat_Light_PopupMenu_Overflow;
+    field public static int Widget_AppCompat_Light_SearchView;
+    field public static int Widget_AppCompat_Light_Spinner_DropDown_ActionBar;
+    field public static int Widget_AppCompat_ListPopupWindow;
+    field public static int Widget_AppCompat_ListView;
+    field public static int Widget_AppCompat_ListView_DropDown;
+    field public static int Widget_AppCompat_ListView_Menu;
+    field public static int Widget_AppCompat_PopupMenu;
+    field public static int Widget_AppCompat_PopupMenu_Overflow;
+    field public static int Widget_AppCompat_PopupWindow;
+    field public static int Widget_AppCompat_ProgressBar;
+    field public static int Widget_AppCompat_ProgressBar_Horizontal;
+    field public static int Widget_AppCompat_RatingBar;
+    field public static int Widget_AppCompat_SearchView;
+    field public static int Widget_AppCompat_SearchView_ActionBar;
+    field public static int Widget_AppCompat_SeekBar;
+    field public static int Widget_AppCompat_Spinner;
+    field public static int Widget_AppCompat_Spinner_DropDown;
+    field public static int Widget_AppCompat_Spinner_DropDown_ActionBar;
+    field public static int Widget_AppCompat_Spinner_Underlined;
+    field public static int Widget_AppCompat_TextView_SpinnerItem;
+    field public static int Widget_AppCompat_Toolbar;
+    field public static int Widget_AppCompat_Toolbar_Button_Navigation;
+  }
+
+  public static final class R.styleable {
+    ctor public R.styleable();
+    field public static final int[] ActionBar;
+    field public static final int[] ActionBarLayout;
+    field public static int ActionBarLayout_android_layout_gravity;
+    field public static int ActionBar_background;
+    field public static int ActionBar_backgroundSplit;
+    field public static int ActionBar_backgroundStacked;
+    field public static int ActionBar_contentInsetEnd;
+    field public static int ActionBar_contentInsetLeft;
+    field public static int ActionBar_contentInsetRight;
+    field public static int ActionBar_contentInsetStart;
+    field public static int ActionBar_customNavigationLayout;
+    field public static int ActionBar_displayOptions;
+    field public static int ActionBar_divider;
+    field public static int ActionBar_elevation;
+    field public static int ActionBar_height;
+    field public static int ActionBar_hideOnContentScroll;
+    field public static int ActionBar_homeAsUpIndicator;
+    field public static int ActionBar_homeLayout;
+    field public static int ActionBar_icon;
+    field public static int ActionBar_indeterminateProgressStyle;
+    field public static int ActionBar_itemPadding;
+    field public static int ActionBar_logo;
+    field public static int ActionBar_navigationMode;
+    field public static int ActionBar_popupTheme;
+    field public static int ActionBar_progressBarPadding;
+    field public static int ActionBar_progressBarStyle;
+    field public static int ActionBar_subtitle;
+    field public static int ActionBar_subtitleTextStyle;
+    field public static int ActionBar_title;
+    field public static int ActionBar_titleTextStyle;
+    field public static final int[] ActionMenuItemView;
+    field public static int ActionMenuItemView_android_minWidth;
+    field public static final int[] ActionMenuView;
+    field public static final int[] ActionMode;
+    field public static int ActionMode_background;
+    field public static int ActionMode_backgroundSplit;
+    field public static int ActionMode_closeItemLayout;
+    field public static int ActionMode_height;
+    field public static int ActionMode_subtitleTextStyle;
+    field public static int ActionMode_titleTextStyle;
+    field public static final int[] ActivityChooserView;
+    field public static int ActivityChooserView_expandActivityOverflowButtonDrawable;
+    field public static int ActivityChooserView_initialActivityCount;
+    field public static final int[] AlertDialog;
+    field public static int AlertDialog_android_layout;
+    field public static int AlertDialog_buttonPanelSideLayout;
+    field public static int AlertDialog_listItemLayout;
+    field public static int AlertDialog_listLayout;
+    field public static int AlertDialog_multiChoiceItemLayout;
+    field public static int AlertDialog_singleChoiceItemLayout;
+    field public static final int[] AppCompatTextView;
+    field public static int AppCompatTextView_android_textAppearance;
+    field public static int AppCompatTextView_textAllCaps;
+    field public static int ButtonBarLayout_allowStacking;
+    field public static final int[] CompoundButton;
+    field public static int CompoundButton_android_button;
+    field public static int CompoundButton_buttonTint;
+    field public static int CompoundButton_buttonTintMode;
+    field public static final int[] DrawerArrowToggle;
+    field public static int DrawerArrowToggle_arrowHeadLength;
+    field public static int DrawerArrowToggle_arrowShaftLength;
+    field public static int DrawerArrowToggle_barLength;
+    field public static int DrawerArrowToggle_color;
+    field public static int DrawerArrowToggle_drawableSize;
+    field public static int DrawerArrowToggle_gapBetweenBars;
+    field public static int DrawerArrowToggle_spinBars;
+    field public static int DrawerArrowToggle_thickness;
+    field public static final int[] LinearLayoutCompat;
+    field public static final int[] LinearLayoutCompat_Layout;
+    field public static int LinearLayoutCompat_Layout_android_layout_gravity;
+    field public static int LinearLayoutCompat_Layout_android_layout_height;
+    field public static int LinearLayoutCompat_Layout_android_layout_weight;
+    field public static int LinearLayoutCompat_Layout_android_layout_width;
+    field public static int LinearLayoutCompat_android_baselineAligned;
+    field public static int LinearLayoutCompat_android_baselineAlignedChildIndex;
+    field public static int LinearLayoutCompat_android_gravity;
+    field public static int LinearLayoutCompat_android_orientation;
+    field public static int LinearLayoutCompat_android_weightSum;
+    field public static int LinearLayoutCompat_divider;
+    field public static int LinearLayoutCompat_dividerPadding;
+    field public static int LinearLayoutCompat_measureWithLargestChild;
+    field public static int LinearLayoutCompat_showDividers;
+    field public static final int[] ListPopupWindow;
+    field public static int ListPopupWindow_android_dropDownHorizontalOffset;
+    field public static int ListPopupWindow_android_dropDownVerticalOffset;
+    field public static final int[] MenuGroup;
+    field public static int MenuGroup_android_checkableBehavior;
+    field public static int MenuGroup_android_enabled;
+    field public static int MenuGroup_android_id;
+    field public static int MenuGroup_android_menuCategory;
+    field public static int MenuGroup_android_orderInCategory;
+    field public static int MenuGroup_android_visible;
+    field public static final int[] MenuItem;
+    field public static int MenuItem_actionLayout;
+    field public static int MenuItem_actionProviderClass;
+    field public static int MenuItem_actionViewClass;
+    field public static int MenuItem_android_alphabeticShortcut;
+    field public static int MenuItem_android_checkable;
+    field public static int MenuItem_android_checked;
+    field public static int MenuItem_android_enabled;
+    field public static int MenuItem_android_icon;
+    field public static int MenuItem_android_id;
+    field public static int MenuItem_android_menuCategory;
+    field public static int MenuItem_android_numericShortcut;
+    field public static int MenuItem_android_onClick;
+    field public static int MenuItem_android_orderInCategory;
+    field public static int MenuItem_android_title;
+    field public static int MenuItem_android_titleCondensed;
+    field public static int MenuItem_android_visible;
+    field public static int MenuItem_showAsAction;
+    field public static final int[] MenuView;
+    field public static int MenuView_android_headerBackground;
+    field public static int MenuView_android_horizontalDivider;
+    field public static int MenuView_android_itemBackground;
+    field public static int MenuView_android_itemIconDisabledAlpha;
+    field public static int MenuView_android_itemTextAppearance;
+    field public static int MenuView_android_verticalDivider;
+    field public static int MenuView_android_windowAnimationStyle;
+    field public static int MenuView_preserveIconSpacing;
+    field public static final int[] PopupWindow;
+    field public static final int[] PopupWindowBackgroundState;
+    field public static int PopupWindowBackgroundState_state_above_anchor;
+    field public static int PopupWindow_android_popupBackground;
+    field public static int PopupWindow_overlapAnchor;
+    field public static final int[] SearchView;
+    field public static int SearchView_android_focusable;
+    field public static int SearchView_android_imeOptions;
+    field public static int SearchView_android_inputType;
+    field public static int SearchView_android_maxWidth;
+    field public static int SearchView_closeIcon;
+    field public static int SearchView_commitIcon;
+    field public static int SearchView_defaultQueryHint;
+    field public static int SearchView_goIcon;
+    field public static int SearchView_iconifiedByDefault;
+    field public static int SearchView_layout;
+    field public static int SearchView_queryBackground;
+    field public static int SearchView_queryHint;
+    field public static int SearchView_searchHintIcon;
+    field public static int SearchView_searchIcon;
+    field public static int SearchView_submitBackground;
+    field public static int SearchView_suggestionRowLayout;
+    field public static int SearchView_voiceIcon;
+    field public static final int[] Spinner;
+    field public static int Spinner_android_dropDownWidth;
+    field public static int Spinner_android_popupBackground;
+    field public static int Spinner_android_prompt;
+    field public static int Spinner_popupTheme;
+    field public static final int[] SwitchCompat;
+    field public static int SwitchCompat_android_textOff;
+    field public static int SwitchCompat_android_textOn;
+    field public static int SwitchCompat_android_thumb;
+    field public static int SwitchCompat_showText;
+    field public static int SwitchCompat_splitTrack;
+    field public static int SwitchCompat_switchMinWidth;
+    field public static int SwitchCompat_switchPadding;
+    field public static int SwitchCompat_switchTextAppearance;
+    field public static int SwitchCompat_thumbTextPadding;
+    field public static int SwitchCompat_track;
+    field public static final int[] TextAppearance;
+    field public static int TextAppearance_android_shadowColor;
+    field public static int TextAppearance_android_shadowDx;
+    field public static int TextAppearance_android_shadowDy;
+    field public static int TextAppearance_android_shadowRadius;
+    field public static int TextAppearance_android_textColor;
+    field public static int TextAppearance_android_textSize;
+    field public static int TextAppearance_android_textStyle;
+    field public static int TextAppearance_android_typeface;
+    field public static int TextAppearance_textAllCaps;
+    field public static final int[] Theme;
+    field public static int Theme_actionBarDivider;
+    field public static int Theme_actionBarItemBackground;
+    field public static int Theme_actionBarPopupTheme;
+    field public static int Theme_actionBarSize;
+    field public static int Theme_actionBarSplitStyle;
+    field public static int Theme_actionBarStyle;
+    field public static int Theme_actionBarTabBarStyle;
+    field public static int Theme_actionBarTabStyle;
+    field public static int Theme_actionBarTabTextStyle;
+    field public static int Theme_actionBarTheme;
+    field public static int Theme_actionBarWidgetTheme;
+    field public static int Theme_actionButtonStyle;
+    field public static int Theme_actionDropDownStyle;
+    field public static int Theme_actionMenuTextAppearance;
+    field public static int Theme_actionMenuTextColor;
+    field public static int Theme_actionModeBackground;
+    field public static int Theme_actionModeCloseButtonStyle;
+    field public static int Theme_actionModeCloseDrawable;
+    field public static int Theme_actionModeCopyDrawable;
+    field public static int Theme_actionModeCutDrawable;
+    field public static int Theme_actionModeFindDrawable;
+    field public static int Theme_actionModePasteDrawable;
+    field public static int Theme_actionModePopupWindowStyle;
+    field public static int Theme_actionModeSelectAllDrawable;
+    field public static int Theme_actionModeShareDrawable;
+    field public static int Theme_actionModeSplitBackground;
+    field public static int Theme_actionModeStyle;
+    field public static int Theme_actionModeWebSearchDrawable;
+    field public static int Theme_actionOverflowButtonStyle;
+    field public static int Theme_actionOverflowMenuStyle;
+    field public static int Theme_activityChooserViewStyle;
+    field public static int Theme_alertDialogButtonGroupStyle;
+    field public static int Theme_alertDialogCenterButtons;
+    field public static int Theme_alertDialogStyle;
+    field public static int Theme_alertDialogTheme;
+    field public static int Theme_android_windowAnimationStyle;
+    field public static int Theme_android_windowIsFloating;
+    field public static int Theme_autoCompleteTextViewStyle;
+    field public static int Theme_borderlessButtonStyle;
+    field public static int Theme_buttonBarButtonStyle;
+    field public static int Theme_buttonBarNegativeButtonStyle;
+    field public static int Theme_buttonBarNeutralButtonStyle;
+    field public static int Theme_buttonBarPositiveButtonStyle;
+    field public static int Theme_buttonBarStyle;
+    field public static int Theme_buttonStyle;
+    field public static int Theme_buttonStyleSmall;
+    field public static int Theme_checkboxStyle;
+    field public static int Theme_checkedTextViewStyle;
+    field public static int Theme_colorAccent;
+    field public static int Theme_colorButtonNormal;
+    field public static int Theme_colorControlActivated;
+    field public static int Theme_colorControlHighlight;
+    field public static int Theme_colorControlNormal;
+    field public static int Theme_colorPrimary;
+    field public static int Theme_colorPrimaryDark;
+    field public static int Theme_colorSwitchThumbNormal;
+    field public static int Theme_controlBackground;
+    field public static int Theme_dialogPreferredPadding;
+    field public static int Theme_dialogTheme;
+    field public static int Theme_dividerHorizontal;
+    field public static int Theme_dividerVertical;
+    field public static int Theme_dropDownListViewStyle;
+    field public static int Theme_dropdownListPreferredItemHeight;
+    field public static int Theme_editTextBackground;
+    field public static int Theme_editTextColor;
+    field public static int Theme_editTextStyle;
+    field public static int Theme_homeAsUpIndicator;
+    field public static int Theme_imageButtonStyle;
+    field public static int Theme_listChoiceBackgroundIndicator;
+    field public static int Theme_listDividerAlertDialog;
+    field public static int Theme_listPopupWindowStyle;
+    field public static int Theme_listPreferredItemHeight;
+    field public static int Theme_listPreferredItemHeightLarge;
+    field public static int Theme_listPreferredItemHeightSmall;
+    field public static int Theme_listPreferredItemPaddingLeft;
+    field public static int Theme_listPreferredItemPaddingRight;
+    field public static int Theme_panelBackground;
+    field public static int Theme_panelMenuListTheme;
+    field public static int Theme_panelMenuListWidth;
+    field public static int Theme_popupMenuStyle;
+    field public static int Theme_popupWindowStyle;
+    field public static int Theme_radioButtonStyle;
+    field public static int Theme_ratingBarStyle;
+    field public static int Theme_searchViewStyle;
+    field public static int Theme_seekBarStyle;
+    field public static int Theme_selectableItemBackground;
+    field public static int Theme_selectableItemBackgroundBorderless;
+    field public static int Theme_spinnerDropDownItemStyle;
+    field public static int Theme_spinnerStyle;
+    field public static int Theme_switchStyle;
+    field public static int Theme_textAppearanceLargePopupMenu;
+    field public static int Theme_textAppearanceListItem;
+    field public static int Theme_textAppearanceListItemSmall;
+    field public static int Theme_textAppearanceSearchResultSubtitle;
+    field public static int Theme_textAppearanceSearchResultTitle;
+    field public static int Theme_textAppearanceSmallPopupMenu;
+    field public static int Theme_textColorAlertDialogListItem;
+    field public static int Theme_textColorSearchUrl;
+    field public static int Theme_toolbarNavigationButtonStyle;
+    field public static int Theme_toolbarStyle;
+    field public static int Theme_windowActionBar;
+    field public static int Theme_windowActionBarOverlay;
+    field public static int Theme_windowActionModeOverlay;
+    field public static int Theme_windowFixedHeightMajor;
+    field public static int Theme_windowFixedHeightMinor;
+    field public static int Theme_windowFixedWidthMajor;
+    field public static int Theme_windowFixedWidthMinor;
+    field public static int Theme_windowMinWidthMajor;
+    field public static int Theme_windowMinWidthMinor;
+    field public static int Theme_windowNoTitle;
+    field public static final int[] Toolbar;
+    field public static int Toolbar_android_gravity;
+    field public static int Toolbar_android_minHeight;
+    field public static int Toolbar_collapseContentDescription;
+    field public static int Toolbar_collapseIcon;
+    field public static int Toolbar_contentInsetEnd;
+    field public static int Toolbar_contentInsetLeft;
+    field public static int Toolbar_contentInsetRight;
+    field public static int Toolbar_contentInsetStart;
+    field public static int Toolbar_logo;
+    field public static int Toolbar_logoDescription;
+    field public static int Toolbar_maxButtonHeight;
+    field public static int Toolbar_navigationContentDescription;
+    field public static int Toolbar_navigationIcon;
+    field public static int Toolbar_popupTheme;
+    field public static int Toolbar_subtitle;
+    field public static int Toolbar_subtitleTextAppearance;
+    field public static int Toolbar_subtitleTextColor;
+    field public static int Toolbar_title;
+    field public static int Toolbar_titleMarginBottom;
+    field public static int Toolbar_titleMarginEnd;
+    field public static int Toolbar_titleMarginStart;
+    field public static int Toolbar_titleMarginTop;
+    field public static int Toolbar_titleMargins;
+    field public static int Toolbar_titleTextAppearance;
+    field public static int Toolbar_titleTextColor;
+    field public static final int[] View;
+    field public static final int[] ViewBackgroundHelper;
+    field public static int ViewBackgroundHelper_android_background;
+    field public static int ViewBackgroundHelper_backgroundTint;
+    field public static int ViewBackgroundHelper_backgroundTintMode;
+    field public static final int[] ViewStubCompat;
+    field public static int ViewStubCompat_android_id;
+    field public static int ViewStubCompat_android_inflatedId;
+    field public static int ViewStubCompat_android_layout;
+    field public static int View_android_focusable;
+    field public static int View_android_theme;
+    field public static int View_paddingEnd;
+    field public static int View_paddingStart;
+    field public static int View_theme;
+  }
+
+}
+
+package android.support.v7.graphics.drawable {
+
+  public class DrawerArrowDrawable extends android.graphics.drawable.Drawable {
+    ctor public DrawerArrowDrawable(android.content.Context);
+    method public void draw(android.graphics.Canvas);
+    method public float getArrowHeadLength();
+    method public float getArrowShaftLength();
+    method public float getBarLength();
+    method public float getBarThickness();
+    method public int getColor();
+    method public int getDirection();
+    method public float getGapSize();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public float getProgress();
+    method public boolean isSpinEnabled();
+    method public void setAlpha(int);
+    method public void setArrowHeadLength(float);
+    method public void setArrowShaftLength(float);
+    method public void setBarLength(float);
+    method public void setBarThickness(float);
+    method public void setColor(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDirection(int);
+    method public void setGapSize(float);
+    method public void setProgress(float);
+    method public void setSpinEnabled(boolean);
+    method public void setVerticalMirror(boolean);
+    field public static final int ARROW_DIRECTION_END = 3; // 0x3
+    field public static final int ARROW_DIRECTION_LEFT = 0; // 0x0
+    field public static final int ARROW_DIRECTION_RIGHT = 1; // 0x1
+    field public static final int ARROW_DIRECTION_START = 2; // 0x2
+  }
+
+}
+
+package android.support.v7.view {
+
+  public abstract class ActionMode {
+    ctor public ActionMode();
+    method public abstract void finish();
+    method public abstract android.view.View getCustomView();
+    method public abstract android.view.Menu getMenu();
+    method public abstract android.view.MenuInflater getMenuInflater();
+    method public abstract java.lang.CharSequence getSubtitle();
+    method public java.lang.Object getTag();
+    method public abstract java.lang.CharSequence getTitle();
+    method public boolean getTitleOptionalHint();
+    method public abstract void invalidate();
+    method public boolean isTitleOptional();
+    method public abstract void setCustomView(android.view.View);
+    method public abstract void setSubtitle(java.lang.CharSequence);
+    method public abstract void setSubtitle(int);
+    method public void setTag(java.lang.Object);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract void setTitle(int);
+    method public void setTitleOptionalHint(boolean);
+  }
+
+  public static abstract interface ActionMode.Callback {
+    method public abstract boolean onActionItemClicked(android.support.v7.view.ActionMode, android.view.MenuItem);
+    method public abstract boolean onCreateActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+    method public abstract void onDestroyActionMode(android.support.v7.view.ActionMode);
+    method public abstract boolean onPrepareActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+  }
+
+  public abstract interface CollapsibleActionView {
+    method public abstract void onActionViewCollapsed();
+    method public abstract void onActionViewExpanded();
+  }
+
+}
+
+package android.support.v7.widget {
+
+  public class ActionMenuView extends android.support.v7.widget.LinearLayoutCompat {
+    ctor public ActionMenuView(android.content.Context);
+    ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
+    method public void dismissPopupMenus();
+    method public android.view.Menu getMenu();
+    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method public int getPopupTheme();
+    method public boolean hideOverflowMenu();
+    method public boolean isOverflowMenuShowing();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDetachedFromWindow();
+    method public void setOnMenuItemClickListener(android.support.v7.widget.ActionMenuView.OnMenuItemClickListener);
+    method public void setOverflowIcon(android.graphics.drawable.Drawable);
+    method public void setPopupTheme(int);
+    method public boolean showOverflowMenu();
+  }
+
+  public static class ActionMenuView.LayoutParams extends android.support.v7.widget.LinearLayoutCompat.LayoutParams {
+    ctor public ActionMenuView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionMenuView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public ActionMenuView.LayoutParams(android.support.v7.widget.ActionMenuView.LayoutParams);
+    ctor public ActionMenuView.LayoutParams(int, int);
+    field public int cellsUsed;
+    field public boolean expandable;
+    field public int extraPixels;
+    field public boolean isOverflowButton;
+    field public boolean preventEdgeOffset;
+  }
+
+  public static abstract interface ActionMenuView.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public class AppCompatAutoCompleteTextView extends android.widget.AutoCompleteTextView {
+    ctor public AppCompatAutoCompleteTextView(android.content.Context);
+    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatButton extends android.widget.Button {
+    ctor public AppCompatButton(android.content.Context);
+    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet, int);
+    method public void setSupportAllCaps(boolean);
+  }
+
+  public class AppCompatCheckBox extends android.widget.CheckBox {
+    ctor public AppCompatCheckBox(android.content.Context);
+    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
+    ctor public AppCompatCheckedTextView(android.content.Context);
+    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatEditText extends android.widget.EditText {
+    ctor public AppCompatEditText(android.content.Context);
+    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageButton extends android.widget.ImageButton {
+    ctor public AppCompatImageButton(android.content.Context);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageView extends android.widget.ImageView {
+    ctor public AppCompatImageView(android.content.Context);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView {
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatRadioButton extends android.widget.RadioButton {
+    ctor public AppCompatRadioButton(android.content.Context);
+    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatRatingBar extends android.widget.RatingBar {
+    ctor public AppCompatRatingBar(android.content.Context);
+    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatSeekBar extends android.widget.SeekBar {
+    ctor public AppCompatSeekBar(android.content.Context);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatSpinner extends android.widget.Spinner {
+    ctor public AppCompatSpinner(android.content.Context);
+    ctor public AppCompatSpinner(android.content.Context, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
+  }
+
+  public class AppCompatTextView extends android.widget.TextView {
+    ctor public AppCompatTextView(android.content.Context);
+    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class LinearLayoutCompat extends android.view.ViewGroup {
+    ctor public LinearLayoutCompat(android.content.Context);
+    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet);
+    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet, int);
+    method public int getBaselineAlignedChildIndex();
+    method public android.graphics.drawable.Drawable getDividerDrawable();
+    method public int getDividerPadding();
+    method public int getOrientation();
+    method public int getShowDividers();
+    method public float getWeightSum();
+    method public boolean isBaselineAligned();
+    method public boolean isMeasureWithLargestChildEnabled();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setBaselineAligned(boolean);
+    method public void setBaselineAlignedChildIndex(int);
+    method public void setDividerDrawable(android.graphics.drawable.Drawable);
+    method public void setDividerPadding(int);
+    method public void setGravity(int);
+    method public void setHorizontalGravity(int);
+    method public void setMeasureWithLargestChildEnabled(boolean);
+    method public void setOrientation(int);
+    method public void setShowDividers(int);
+    method public void setVerticalGravity(int);
+    method public void setWeightSum(float);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int SHOW_DIVIDER_BEGINNING = 1; // 0x1
+    field public static final int SHOW_DIVIDER_END = 4; // 0x4
+    field public static final int SHOW_DIVIDER_MIDDLE = 2; // 0x2
+    field public static final int SHOW_DIVIDER_NONE = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class LinearLayoutCompat.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public LinearLayoutCompat.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public LinearLayoutCompat.LayoutParams(int, int);
+    ctor public LinearLayoutCompat.LayoutParams(int, int, float);
+    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public LinearLayoutCompat.LayoutParams(android.support.v7.widget.LinearLayoutCompat.LayoutParams);
+    field public int gravity;
+    field public float weight;
+  }
+
+  public class ListPopupWindow {
+    ctor public ListPopupWindow(android.content.Context);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int);
+    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int, int);
+    method public void clearListSelection();
+    method public android.view.View.OnTouchListener createDragToOpenListener(android.view.View);
+    method public void dismiss();
+    method public android.view.View getAnchorView();
+    method public int getAnimationStyle();
+    method public android.graphics.drawable.Drawable getBackground();
+    method public int getHeight();
+    method public int getHorizontalOffset();
+    method public int getInputMethodMode();
+    method public android.widget.ListView getListView();
+    method public int getPromptPosition();
+    method public java.lang.Object getSelectedItem();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public android.view.View getSelectedView();
+    method public int getSoftInputMode();
+    method public int getVerticalOffset();
+    method public int getWidth();
+    method public boolean isInputMethodNotNeeded();
+    method public boolean isModal();
+    method public boolean isShowing();
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyPreIme(int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public boolean performItemClick(int);
+    method public void postShow();
+    method public void setAdapter(android.widget.ListAdapter);
+    method public void setAnchorView(android.view.View);
+    method public void setAnimationStyle(int);
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setContentWidth(int);
+    method public void setDropDownGravity(int);
+    method public void setHeight(int);
+    method public void setHorizontalOffset(int);
+    method public void setInputMethodMode(int);
+    method public void setListSelector(android.graphics.drawable.Drawable);
+    method public void setModal(boolean);
+    method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
+    method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
+    method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public void setPromptPosition(int);
+    method public void setPromptView(android.view.View);
+    method public void setSelection(int);
+    method public void setSoftInputMode(int);
+    method public void setVerticalOffset(int);
+    method public void setWidth(int);
+    method public void setWindowLayoutType(int);
+    method public void show();
+    field public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; // 0x0
+    field public static final int INPUT_METHOD_NEEDED = 1; // 0x1
+    field public static final int INPUT_METHOD_NOT_NEEDED = 2; // 0x2
+    field public static final int MATCH_PARENT = -1; // 0xffffffff
+    field public static final int POSITION_PROMPT_ABOVE = 0; // 0x0
+    field public static final int POSITION_PROMPT_BELOW = 1; // 0x1
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public class PopupMenu {
+    ctor public PopupMenu(android.content.Context, android.view.View);
+    ctor public PopupMenu(android.content.Context, android.view.View, int);
+    ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
+    method public void dismiss();
+    method public android.view.View.OnTouchListener getDragToOpenListener();
+    method public int getGravity();
+    method public android.view.Menu getMenu();
+    method public android.view.MenuInflater getMenuInflater();
+    method public void inflate(int);
+    method public void setGravity(int);
+    method public void setOnDismissListener(android.support.v7.widget.PopupMenu.OnDismissListener);
+    method public void setOnMenuItemClickListener(android.support.v7.widget.PopupMenu.OnMenuItemClickListener);
+    method public void show();
+  }
+
+  public static abstract interface PopupMenu.OnDismissListener {
+    method public abstract void onDismiss(android.support.v7.widget.PopupMenu);
+  }
+
+  public static abstract interface PopupMenu.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public class SearchView extends android.support.v7.widget.LinearLayoutCompat implements android.support.v7.view.CollapsibleActionView {
+    ctor public SearchView(android.content.Context);
+    ctor public SearchView(android.content.Context, android.util.AttributeSet);
+    ctor public SearchView(android.content.Context, android.util.AttributeSet, int);
+    method public int getImeOptions();
+    method public int getInputType();
+    method public int getMaxWidth();
+    method public java.lang.CharSequence getQuery();
+    method public java.lang.CharSequence getQueryHint();
+    method public android.support.v4.widget.CursorAdapter getSuggestionsAdapter();
+    method public boolean isIconfiedByDefault();
+    method public boolean isIconified();
+    method public boolean isQueryRefinementEnabled();
+    method public boolean isSubmitButtonEnabled();
+    method public void onActionViewCollapsed();
+    method public void onActionViewExpanded();
+    method public void setIconified(boolean);
+    method public void setIconifiedByDefault(boolean);
+    method public void setImeOptions(int);
+    method public void setInputType(int);
+    method public void setMaxWidth(int);
+    method public void setOnCloseListener(android.support.v7.widget.SearchView.OnCloseListener);
+    method public void setOnQueryTextFocusChangeListener(android.view.View.OnFocusChangeListener);
+    method public void setOnQueryTextListener(android.support.v7.widget.SearchView.OnQueryTextListener);
+    method public void setOnSearchClickListener(android.view.View.OnClickListener);
+    method public void setOnSuggestionListener(android.support.v7.widget.SearchView.OnSuggestionListener);
+    method public void setQuery(java.lang.CharSequence, boolean);
+    method public void setQueryHint(java.lang.CharSequence);
+    method public void setQueryRefinementEnabled(boolean);
+    method public void setSearchableInfo(android.app.SearchableInfo);
+    method public void setSubmitButtonEnabled(boolean);
+    method public void setSuggestionsAdapter(android.support.v4.widget.CursorAdapter);
+  }
+
+  public static abstract interface SearchView.OnCloseListener {
+    method public abstract boolean onClose();
+  }
+
+  public static abstract interface SearchView.OnQueryTextListener {
+    method public abstract boolean onQueryTextChange(java.lang.String);
+    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  }
+
+  public static abstract interface SearchView.OnSuggestionListener {
+    method public abstract boolean onSuggestionClick(int);
+    method public abstract boolean onSuggestionSelect(int);
+  }
+
+  public class ShareActionProvider extends android.support.v4.view.ActionProvider {
+    ctor public ShareActionProvider(android.content.Context);
+    method public android.view.View onCreateActionView();
+    method public void setOnShareTargetSelectedListener(android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener);
+    method public void setShareHistoryFileName(java.lang.String);
+    method public void setShareIntent(android.content.Intent);
+    field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+  }
+
+  public static abstract interface ShareActionProvider.OnShareTargetSelectedListener {
+    method public abstract boolean onShareTargetSelected(android.support.v7.widget.ShareActionProvider, android.content.Intent);
+  }
+
+  public class SwitchCompat extends android.widget.CompoundButton {
+    ctor public SwitchCompat(android.content.Context);
+    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet, int);
+    method public boolean getShowText();
+    method public boolean getSplitTrack();
+    method public int getSwitchMinWidth();
+    method public int getSwitchPadding();
+    method public java.lang.CharSequence getTextOff();
+    method public java.lang.CharSequence getTextOn();
+    method public android.graphics.drawable.Drawable getThumbDrawable();
+    method public int getThumbTextPadding();
+    method public android.graphics.drawable.Drawable getTrackDrawable();
+    method public void onMeasure(int, int);
+    method public void setShowText(boolean);
+    method public void setSplitTrack(boolean);
+    method public void setSwitchMinWidth(int);
+    method public void setSwitchPadding(int);
+    method public void setSwitchTextAppearance(android.content.Context, int);
+    method public void setSwitchTypeface(android.graphics.Typeface, int);
+    method public void setSwitchTypeface(android.graphics.Typeface);
+    method public void setTextOff(java.lang.CharSequence);
+    method public void setTextOn(java.lang.CharSequence);
+    method public void setThumbDrawable(android.graphics.drawable.Drawable);
+    method public void setThumbResource(int);
+    method public void setThumbTextPadding(int);
+    method public void setTrackDrawable(android.graphics.drawable.Drawable);
+    method public void setTrackResource(int);
+  }
+
+  public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
+    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
+  public static final class ThemedSpinnerAdapter.Helper {
+    ctor public ThemedSpinnerAdapter.Helper(android.content.Context);
+    method public android.view.LayoutInflater getDropDownViewInflater();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
+  public class Toolbar extends android.view.ViewGroup {
+    ctor public Toolbar(android.content.Context);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
+    method public void collapseActionView();
+    method public void dismissPopupMenus();
+    method public int getContentInsetEnd();
+    method public int getContentInsetLeft();
+    method public int getContentInsetRight();
+    method public int getContentInsetStart();
+    method public android.graphics.drawable.Drawable getLogo();
+    method public java.lang.CharSequence getLogoDescription();
+    method public android.view.Menu getMenu();
+    method public java.lang.CharSequence getNavigationContentDescription();
+    method public android.graphics.drawable.Drawable getNavigationIcon();
+    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method public int getPopupTheme();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public boolean hasExpandedActionView();
+    method public boolean hideOverflowMenu();
+    method public void inflateMenu(int);
+    method public boolean isOverflowMenuShowing();
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setContentInsetsAbsolute(int, int);
+    method public void setContentInsetsRelative(int, int);
+    method public void setLogo(int);
+    method public void setLogo(android.graphics.drawable.Drawable);
+    method public void setLogoDescription(int);
+    method public void setLogoDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(int);
+    method public void setNavigationContentDescription(java.lang.CharSequence);
+    method public void setNavigationIcon(int);
+    method public void setNavigationIcon(android.graphics.drawable.Drawable);
+    method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setOnMenuItemClickListener(android.support.v7.widget.Toolbar.OnMenuItemClickListener);
+    method public void setOverflowIcon(android.graphics.drawable.Drawable);
+    method public void setPopupTheme(int);
+    method public void setSubtitle(int);
+    method public void setSubtitle(java.lang.CharSequence);
+    method public void setSubtitleTextAppearance(android.content.Context, int);
+    method public void setSubtitleTextColor(int);
+    method public void setTitle(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitleTextAppearance(android.content.Context, int);
+    method public void setTitleTextColor(int);
+    method public boolean showOverflowMenu();
+  }
+
+  public static class Toolbar.LayoutParams extends android.support.v7.app.ActionBar.LayoutParams {
+    ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar.LayoutParams(int, int);
+    ctor public Toolbar.LayoutParams(int, int, int);
+    ctor public Toolbar.LayoutParams(int);
+    ctor public Toolbar.LayoutParams(android.support.v7.widget.Toolbar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
+  }
+
+  public static abstract interface Toolbar.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
+  public static class Toolbar.SavedState extends android.view.View.BaseSavedState {
+    ctor public Toolbar.SavedState(android.os.Parcel);
+    ctor public Toolbar.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v7.widget.Toolbar.SavedState> CREATOR;
+  }
+
+}
+
diff --git a/v7/appcompat/api/current.txt b/v7/appcompat/api/current.txt
index 336e3a7..8f35544 100644
--- a/v7/appcompat/api/current.txt
+++ b/v7/appcompat/api/current.txt
@@ -368,6 +368,7 @@
     field public static int alertDialogCenterButtons;
     field public static int alertDialogStyle;
     field public static int alertDialogTheme;
+    field public static int allowStacking;
     field public static int arrowHeadLength;
     field public static int arrowShaftLength;
     field public static int autoCompleteTextViewStyle;
@@ -435,6 +436,7 @@
     field public static int homeLayout;
     field public static int icon;
     field public static int iconifiedByDefault;
+    field public static int imageButtonStyle;
     field public static int indeterminateProgressStyle;
     field public static int initialActivityCount;
     field public static int isLightTheme;
@@ -477,6 +479,7 @@
     field public static int searchHintIcon;
     field public static int searchIcon;
     field public static int searchViewStyle;
+    field public static int seekBarStyle;
     field public static int selectableItemBackground;
     field public static int selectableItemBackgroundBorderless;
     field public static int showAsAction;
@@ -540,6 +543,7 @@
     field public static int abc_action_bar_embed_tabs;
     field public static int abc_action_bar_embed_tabs_pre_jb;
     field public static int abc_action_bar_expanded_action_views_exclusive;
+    field public static int abc_allow_stacked_button_bar;
     field public static int abc_config_actionMenuItemAllCaps;
     field public static int abc_config_allowActionMenuItemTextWithIcon;
     field public static int abc_config_closeDialogWhenTouchOutside;
@@ -646,6 +650,10 @@
     field public static int abc_control_corner_material;
     field public static int abc_control_inset_material;
     field public static int abc_control_padding_material;
+    field public static int abc_dialog_fixed_height_major;
+    field public static int abc_dialog_fixed_height_minor;
+    field public static int abc_dialog_fixed_width_major;
+    field public static int abc_dialog_fixed_width_minor;
     field public static int abc_dialog_list_padding_vertical_material;
     field public static int abc_dialog_min_width_major;
     field public static int abc_dialog_min_width_minor;
@@ -664,6 +672,9 @@
     field public static int abc_panel_menu_list_width;
     field public static int abc_search_view_preferred_width;
     field public static int abc_search_view_text_min_width;
+    field public static int abc_seekbar_track_background_height_material;
+    field public static int abc_seekbar_track_progress_height_material;
+    field public static int abc_select_dialog_padding_start_material;
     field public static int abc_switch_padding;
     field public static int abc_text_size_body_1_material;
     field public static int abc_text_size_body_2_material;
@@ -682,10 +693,6 @@
     field public static int abc_text_size_subtitle_material_toolbar;
     field public static int abc_text_size_title_material;
     field public static int abc_text_size_title_material_toolbar;
-    field public static int dialog_fixed_height_major;
-    field public static int dialog_fixed_height_minor;
-    field public static int dialog_fixed_width_major;
-    field public static int dialog_fixed_width_minor;
     field public static int disabled_alpha_material_dark;
     field public static int disabled_alpha_material_light;
     field public static int highlight_alpha_material_colored;
@@ -748,6 +755,13 @@
     field public static int abc_menu_hardkey_panel_mtrl_mult;
     field public static int abc_popup_background_mtrl_mult;
     field public static int abc_ratingbar_full_material;
+    field public static int abc_scrubber_control_off_mtrl_alpha;
+    field public static int abc_scrubber_control_to_pressed_mtrl_000;
+    field public static int abc_scrubber_control_to_pressed_mtrl_005;
+    field public static int abc_scrubber_primary_mtrl_alpha;
+    field public static int abc_scrubber_track_mtrl_alpha;
+    field public static int abc_seekbar_thumb_material;
+    field public static int abc_seekbar_track_material;
     field public static int abc_spinner_mtrl_am_alpha;
     field public static int abc_spinner_textfield_background_material;
     field public static int abc_switch_thumb_material;
@@ -821,6 +835,8 @@
     field public static int progress_horizontal;
     field public static int radio;
     field public static int screen;
+    field public static int scrollIndicatorDown;
+    field public static int scrollIndicatorUp;
     field public static int scrollView;
     field public static int search_badge;
     field public static int search_bar;
@@ -837,6 +853,7 @@
     field public static int showCustom;
     field public static int showHome;
     field public static int showTitle;
+    field public static int spacer;
     field public static int split_action_bar;
     field public static int src_atop;
     field public static int src_in;
@@ -877,6 +894,7 @@
     field public static int abc_action_mode_close_item_material;
     field public static int abc_activity_chooser_view;
     field public static int abc_activity_chooser_view_list_item;
+    field public static int abc_alert_dialog_button_bar_material;
     field public static int abc_alert_dialog_material;
     field public static int abc_dialog_title_material;
     field public static int abc_expanded_menu_layout;
@@ -916,6 +934,8 @@
     field public static int abc_action_mode_done;
     field public static int abc_activity_chooser_view_see_all;
     field public static int abc_activitychooserview_choose_application;
+    field public static int abc_capital_off;
+    field public static int abc_capital_on;
     field public static int abc_search_hint;
     field public static int abc_searchview_description_clear;
     field public static int abc_searchview_description_query;
@@ -1047,6 +1067,7 @@
     field public static int Base_Widget_AppCompat_DrawerArrowToggle_Common;
     field public static int Base_Widget_AppCompat_DropDownItem_Spinner;
     field public static int Base_Widget_AppCompat_EditText;
+    field public static int Base_Widget_AppCompat_ImageButton;
     field public static int Base_Widget_AppCompat_Light_ActionBar;
     field public static int Base_Widget_AppCompat_Light_ActionBar_Solid;
     field public static int Base_Widget_AppCompat_Light_ActionBar_TabBar;
@@ -1067,6 +1088,7 @@
     field public static int Base_Widget_AppCompat_RatingBar;
     field public static int Base_Widget_AppCompat_SearchView;
     field public static int Base_Widget_AppCompat_SearchView_ActionBar;
+    field public static int Base_Widget_AppCompat_SeekBar;
     field public static int Base_Widget_AppCompat_Spinner;
     field public static int Base_Widget_AppCompat_Spinner_Underlined;
     field public static int Base_Widget_AppCompat_TextView_SpinnerItem;
@@ -1084,7 +1106,6 @@
     field public static int Platform_Widget_AppCompat_Spinner;
     field public static int RtlOverlay_DialogWindowTitle_AppCompat;
     field public static int RtlOverlay_Widget_AppCompat_ActionBar_TitleItem;
-    field public static int RtlOverlay_Widget_AppCompat_ActionButton_Overflow;
     field public static int RtlOverlay_Widget_AppCompat_DialogTitle_Icon;
     field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem;
     field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem_InternalGroup;
@@ -1095,6 +1116,8 @@
     field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Icon2;
     field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Query;
     field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Text;
+    field public static int RtlUnderlay_Widget_AppCompat_ActionButton;
+    field public static int RtlUnderlay_Widget_AppCompat_ActionButton_Overflow;
     field public static int TextAppearance_AppCompat;
     field public static int TextAppearance_AppCompat_Body1;
     field public static int TextAppearance_AppCompat_Body2;
@@ -1191,6 +1214,7 @@
     field public static int Widget_AppCompat_DrawerArrowToggle;
     field public static int Widget_AppCompat_DropDownItem_Spinner;
     field public static int Widget_AppCompat_EditText;
+    field public static int Widget_AppCompat_ImageButton;
     field public static int Widget_AppCompat_Light_ActionBar;
     field public static int Widget_AppCompat_Light_ActionBar_Solid;
     field public static int Widget_AppCompat_Light_ActionBar_Solid_Inverse;
@@ -1225,6 +1249,7 @@
     field public static int Widget_AppCompat_RatingBar;
     field public static int Widget_AppCompat_SearchView;
     field public static int Widget_AppCompat_SearchView_ActionBar;
+    field public static int Widget_AppCompat_SeekBar;
     field public static int Widget_AppCompat_Spinner;
     field public static int Widget_AppCompat_Spinner_DropDown;
     field public static int Widget_AppCompat_Spinner_DropDown_ActionBar;
@@ -1289,6 +1314,7 @@
     field public static final int[] AppCompatTextView;
     field public static int AppCompatTextView_android_textAppearance;
     field public static int AppCompatTextView_textAllCaps;
+    field public static int ButtonBarLayout_allowStacking;
     field public static final int[] CompoundButton;
     field public static int CompoundButton_android_button;
     field public static int CompoundButton_buttonTint;
@@ -1379,6 +1405,7 @@
     field public static int SearchView_voiceIcon;
     field public static final int[] Spinner;
     field public static int Spinner_android_dropDownWidth;
+    field public static int Spinner_android_entries;
     field public static int Spinner_android_popupBackground;
     field public static int Spinner_android_prompt;
     field public static int Spinner_popupTheme;
@@ -1394,6 +1421,10 @@
     field public static int SwitchCompat_thumbTextPadding;
     field public static int SwitchCompat_track;
     field public static final int[] TextAppearance;
+    field public static int TextAppearance_android_shadowColor;
+    field public static int TextAppearance_android_shadowDx;
+    field public static int TextAppearance_android_shadowDy;
+    field public static int TextAppearance_android_shadowRadius;
     field public static int TextAppearance_android_textColor;
     field public static int TextAppearance_android_textSize;
     field public static int TextAppearance_android_textStyle;
@@ -1467,6 +1498,7 @@
     field public static int Theme_editTextColor;
     field public static int Theme_editTextStyle;
     field public static int Theme_homeAsUpIndicator;
+    field public static int Theme_imageButtonStyle;
     field public static int Theme_listChoiceBackgroundIndicator;
     field public static int Theme_listDividerAlertDialog;
     field public static int Theme_listPopupWindowStyle;
@@ -1483,6 +1515,7 @@
     field public static int Theme_radioButtonStyle;
     field public static int Theme_ratingBarStyle;
     field public static int Theme_searchViewStyle;
+    field public static int Theme_seekBarStyle;
     field public static int Theme_selectableItemBackground;
     field public static int Theme_selectableItemBackgroundBorderless;
     field public static int Theme_spinnerDropDownItemStyle;
@@ -1565,6 +1598,7 @@
     method public int getDirection();
     method public float getGapSize();
     method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
     method public float getProgress();
     method public boolean isSpinEnabled();
     method public void setAlpha(int);
@@ -1690,6 +1724,18 @@
     ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
   }
 
+  public class AppCompatImageButton extends android.widget.ImageButton {
+    ctor public AppCompatImageButton(android.content.Context);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageView extends android.widget.ImageView {
+    ctor public AppCompatImageView(android.content.Context);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+  }
+
   public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView {
     ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
     ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
@@ -1708,6 +1754,12 @@
     ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet, int);
   }
 
+  public class AppCompatSeekBar extends android.widget.SeekBar {
+    ctor public AppCompatSeekBar(android.content.Context);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
+  }
+
   public class AppCompatSpinner extends android.widget.Spinner {
     ctor public AppCompatSpinner(android.content.Context);
     ctor public AppCompatSpinner(android.content.Context, int);
@@ -1817,6 +1869,7 @@
     method public void setSoftInputMode(int);
     method public void setVerticalOffset(int);
     method public void setWidth(int);
+    method public void setWindowLayoutType(int);
     method public void show();
     field public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; // 0x0
     field public static final int INPUT_METHOD_NEEDED = 1; // 0x1
diff --git a/v7/appcompat/res-public/values/public_attrs.xml b/v7/appcompat/res-public/values/public_attrs.xml
index f8fae53..3c812d7 100644
--- a/v7/appcompat/res-public/values/public_attrs.xml
+++ b/v7/appcompat/res-public/values/public_attrs.xml
@@ -99,8 +99,6 @@
      <public type="attr" name="dividerVertical"/>
      <public type="attr" name="drawableSize"/>
      <public type="attr" name="drawerArrowStyle"/>
-     <public type="attr" name="dropdownListPreferredItemHeight"/>
-     <public type="attr" name="dropDownListViewStyle"/>
      <public type="attr" name="editTextBackground"/>
      <public type="attr" name="editTextColor"/>
      <public type="attr" name="editTextStyle"/>
@@ -115,6 +113,7 @@
      <public type="attr" name="iconifiedByDefault"/>
      <public type="attr" name="indeterminateProgressStyle"/>
      <public type="attr" name="isLightTheme"/>
+     <public type="attr" name="imageButtonStyle"/>
      <public type="attr" name="itemPadding"/>
      <public type="attr" name="layout"/>
      <public type="attr" name="listChoiceBackgroundIndicator"/>
diff --git a/v7/appcompat/res-public/values/public_styles.xml b/v7/appcompat/res-public/values/public_styles.xml
index 4b42d0f..991ab54 100644
--- a/v7/appcompat/res-public/values/public_styles.xml
+++ b/v7/appcompat/res-public/values/public_styles.xml
@@ -102,6 +102,7 @@
     <public type="style" name="Widget.AppCompat.DrawerArrowToggle"/>
     <public type="style" name="Widget.AppCompat.DropDownItem.Spinner"/>
     <public type="style" name="Widget.AppCompat.EditText"/>
+    <public type="style" name="Widget.AppCompat.ImageButton"/>
     <public type="style" name="Widget.AppCompat.Light.ActionBar"/>
     <public type="style" name="Widget.AppCompat.Light.ActionBar.Solid"/>
     <public type="style" name="Widget.AppCompat.Light.ActionBar.Solid.Inverse"/>
@@ -135,6 +136,7 @@
     <public type="style" name="Widget.AppCompat.RatingBar"/>
     <public type="style" name="Widget.AppCompat.SearchView"/>
     <public type="style" name="Widget.AppCompat.SearchView.ActionBar"/>
+    <public type="style" name="Widget.AppCompat.SeekBar"/>
     <public type="style" name="Widget.AppCompat.Spinner"/>
     <public type="style" name="Widget.AppCompat.Spinner.DropDown"/>
     <public type="style" name="Widget.AppCompat.Spinner.DropDown.ActionBar"/>
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..4efe298
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..543dec3
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..9930b3a
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..4cfb1a7
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..32ddf7a
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png
index 56436a1..6ad9b1d 100644
--- a/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..10df639
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..f83b1ef
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..e9efb20f
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..a4ab0a1
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..db9e172
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png
index fcd81de..00c81fc 100644
--- a/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..138f643
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..cd41d74
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..8d67525
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..2b4734d
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..805cb29
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png
index cd1396b..f0752d2 100644
--- a/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..5268745
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..adffc14
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..f3d16d5
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..6a82af5
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..c3791fc
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png
index 96bec46..c74b3fc 100644
--- a/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..e5a43bb
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..eeb37c1
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png
index c2393ab..85c81c1 100644
--- a/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable/abc_seekbar_thumb_material.xml b/v7/appcompat/res/drawable/abc_seekbar_thumb_material.xml
new file mode 100644
index 0000000..7fea83bc
--- /dev/null
+++ b/v7/appcompat/res/drawable/abc_seekbar_thumb_material.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:constantSize="true">
+    <item android:state_enabled="false" android:state_pressed="true">
+        <bitmap android:src="@drawable/abc_scrubber_control_off_mtrl_alpha"
+                android:gravity="center"/>
+    </item>
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/abc_scrubber_control_off_mtrl_alpha"
+                android:gravity="center"/>
+    </item>
+    <item android:state_pressed="true">
+        <bitmap android:src="@drawable/abc_scrubber_control_to_pressed_mtrl_005"
+                android:gravity="center"/>
+    </item>
+    <item>
+        <bitmap android:src="@drawable/abc_scrubber_control_to_pressed_mtrl_000"
+                android:gravity="center"/>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/abc_seekbar_track_material.xml b/v7/appcompat/res/drawable/abc_seekbar_track_material.xml
new file mode 100644
index 0000000..e68ac03
--- /dev/null
+++ b/v7/appcompat/res/drawable/abc_seekbar_track_material.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/background"
+          android:drawable="@drawable/abc_scrubber_track_mtrl_alpha"/>
+    <item android:id="@android:id/secondaryProgress">
+        <scale android:scaleWidth="100%">
+            <selector>
+                <item android:state_enabled="false">
+                    <color android:color="@android:color/transparent"/>
+                </item>
+                <item android:drawable="@drawable/abc_scrubber_primary_mtrl_alpha"/>
+            </selector>
+        </scale>
+    </item>
+    <item android:id="@android:id/progress">
+        <scale android:scaleWidth="100%">
+            <selector>
+                <item android:state_enabled="false">
+                    <color android:color="@android:color/transparent"/>
+                </item>
+                <item android:drawable="@drawable/abc_scrubber_primary_mtrl_alpha"/>
+            </selector>
+        </scale>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_action_menu_item_layout.xml b/v7/appcompat/res/layout/abc_action_menu_item_layout.xml
index 150ea50..283358a 100644
--- a/v7/appcompat/res/layout/abc_action_menu_item_layout.xml
+++ b/v7/appcompat/res/layout/abc_action_menu_item_layout.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.view.menu.ActionMenuItemView
+<android.support.v7.view.menu.ActionMenuItemView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/v7/appcompat/res/layout/abc_action_mode_bar.xml b/v7/appcompat/res/layout/abc_action_mode_bar.xml
index 34b56a1..dc1f1ba 100644
--- a/v7/appcompat/res/layout/abc_action_mode_bar.xml
+++ b/v7/appcompat/res/layout/abc_action_mode_bar.xml
@@ -16,7 +16,7 @@
 ** limitations under the License.
 */
 -->
-<android.support.v7.internal.widget.ActionBarContextView
+<android.support.v7.widget.ActionBarContextView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml b/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
index dfc4deb..2944d983 100644
--- a/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
+++ b/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
@@ -14,13 +14,13 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.widget.TintImageView
-             xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/action_mode_close_button"
-             android:contentDescription="@string/abc_action_mode_done"
-             android:focusable="true"
-             android:clickable="true"
-             android:src="?attr/actionModeCloseDrawable"
-             style="?attr/actionModeCloseButtonStyle"
-             android:layout_width="wrap_content"
-             android:layout_height="match_parent" />
\ No newline at end of file
+<ImageView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/action_mode_close_button"
+        android:contentDescription="@string/abc_action_mode_done"
+        android:focusable="true"
+        android:clickable="true"
+        android:src="?attr/actionModeCloseDrawable"
+        style="?attr/actionModeCloseButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_activity_chooser_view.xml b/v7/appcompat/res/layout/abc_activity_chooser_view.xml
index 85fd94e..2522f1a 100644
--- a/v7/appcompat/res/layout/abc_activity_chooser_view.xml
+++ b/v7/appcompat/res/layout/abc_activity_chooser_view.xml
@@ -17,7 +17,7 @@
 */
 -->
 <view xmlns:android="http://schemas.android.com/apk/res/android"
-    class="android.support.v7.internal.widget.ActivityChooserView$InnerLayout"
+    class="android.support.v7.widget.ActivityChooserView$InnerLayout"
     android:id="@+id/activity_chooser_view_content"
     android:layout_width="wrap_content"
     android:layout_height="match_parent"
diff --git a/v7/appcompat/res/layout/abc_alert_dialog_button_bar_material.xml b/v7/appcompat/res/layout/abc_alert_dialog_button_bar_material.xml
new file mode 100644
index 0000000..d32ad10
--- /dev/null
+++ b/v7/appcompat/res/layout/abc_alert_dialog_button_bar_material.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<android.support.v7.widget.ButtonBarLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/buttonPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layoutDirection="locale"
+    android:orientation="horizontal"
+    android:paddingLeft="12dp"
+    android:paddingRight="12dp"
+    android:paddingTop="4dp"
+    android:paddingBottom="4dp"
+    android:gravity="bottom"
+    app:allowStacking="@bool/abc_allow_stacked_button_bar"
+    style="?attr/buttonBarStyle">
+
+    <Button
+        android:id="@android:id/button3"
+        style="?attr/buttonBarNeutralButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <android.support.v4.widget.Space
+        android:id="@+id/spacer"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:visibility="invisible" />
+
+    <Button
+        android:id="@android:id/button2"
+        style="?attr/buttonBarNegativeButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button
+        android:id="@android:id/button1"
+        style="?attr/buttonBarPositiveButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</android.support.v7.widget.ButtonBarLayout>
diff --git a/v7/appcompat/res/layout/abc_alert_dialog_material.xml b/v7/appcompat/res/layout/abc_alert_dialog_material.xml
index 9ba81fd..3237533 100644
--- a/v7/appcompat/res/layout/abc_alert_dialog_material.xml
+++ b/v7/appcompat/res/layout/abc_alert_dialog_material.xml
@@ -45,7 +45,7 @@
                     android:src="@null"
                     style="@style/RtlOverlay.Widget.AppCompat.DialogTitle.Icon"/>
 
-            <android.support.v7.internal.widget.DialogTitle
+            <android.support.v7.widget.DialogTitle
                     android:id="@+id/alertTitle"
                     style="?attr/android:windowTitleStyle"
                     android:singleLine="true"
@@ -65,7 +65,14 @@
             android:layout_weight="1"
             android:minHeight="48dp">
 
-        <ScrollView
+        <View android:id="@+id/scrollIndicatorUp"
+              android:visibility="gone"
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:layout_gravity="top"
+              android:background="?attr/colorControlHighlight"/>
+
+        <android.support.v4.widget.NestedScrollView
                 android:id="@+id/scrollView"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -91,7 +98,14 @@
                         android:layout_width="0dp"
                         android:layout_height="@dimen/abc_dialog_padding_top_material"/>
             </LinearLayout>
-        </ScrollView>
+        </android.support.v4.widget.NestedScrollView>
+
+        <View android:id="@+id/scrollIndicatorDown"
+              android:visibility="gone"
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:layout_gravity="bottom"
+              android:background="?attr/colorControlHighlight"/>
 
     </FrameLayout>
 
@@ -108,41 +122,6 @@
                 android:layout_height="wrap_content"/>
     </FrameLayout>
 
-    <LinearLayout
-            android:id="@+id/buttonPanel"
-            style="?attr/buttonBarStyle"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layoutDirection="locale"
-            android:orientation="horizontal"
-            android:paddingLeft="12dp"
-            android:paddingRight="12dp"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dp"
-            android:gravity="bottom">
+    <include layout="@layout/abc_alert_dialog_button_bar_material" />
 
-        <Button
-                android:id="@android:id/button3"
-                style="?attr/buttonBarNeutralButtonStyle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-
-        <android.support.v4.widget.Space
-                android:layout_width="0dp"
-                android:layout_height="0dp"
-                android:layout_weight="1"
-                android:visibility="invisible"/>
-
-        <Button
-                android:id="@android:id/button2"
-                style="?attr/buttonBarNegativeButtonStyle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-
-        <Button
-                android:id="@android:id/button1"
-                style="?attr/buttonBarPositiveButtonStyle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-    </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_dialog_title_material.xml b/v7/appcompat/res/layout/abc_dialog_title_material.xml
index 068b9e9..1ea20c5 100644
--- a/v7/appcompat/res/layout/abc_dialog_title_material.xml
+++ b/v7/appcompat/res/layout/abc_dialog_title_material.xml
@@ -19,7 +19,7 @@
 enabled.
 -->
 
-<android.support.v7.internal.widget.FitWindowsLinearLayout
+<android.support.v7.widget.FitWindowsLinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_height="match_parent"
         android:layout_width="match_parent"
@@ -44,4 +44,4 @@
             android:layout_height="wrap_content"
             android:layout_weight="1"/>
 
-</android.support.v7.internal.widget.FitWindowsLinearLayout>
\ No newline at end of file
+</android.support.v7.widget.FitWindowsLinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_expanded_menu_layout.xml b/v7/appcompat/res/layout/abc_expanded_menu_layout.xml
index 371151f..560ada6 100644
--- a/v7/appcompat/res/layout/abc_expanded_menu_layout.xml
+++ b/v7/appcompat/res/layout/abc_expanded_menu_layout.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.view.menu.ExpandedMenuView
+<android.support.v7.view.menu.ExpandedMenuView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/expanded_menu"
         android:layout_width="?attr/panelMenuListWidth"
diff --git a/v7/appcompat/res/layout/abc_list_menu_item_layout.xml b/v7/appcompat/res/layout/abc_list_menu_item_layout.xml
index 1cee43e..c85469d 100644
--- a/v7/appcompat/res/layout/abc_list_menu_item_layout.xml
+++ b/v7/appcompat/res/layout/abc_list_menu_item_layout.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.view.menu.ListMenuItemView
+<android.support.v7.view.menu.ListMenuItemView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="?attr/listPreferredItemHeightSmall">
@@ -57,4 +57,4 @@
 
     <!-- Checkbox, and/or radio button will be inserted here. -->
 
-</android.support.v7.internal.view.menu.ListMenuItemView>
+</android.support.v7.view.menu.ListMenuItemView>
diff --git a/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml b/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
index 76820e0..47125fe 100644
--- a/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
+++ b/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.view.menu.ListMenuItemView
+<android.support.v7.view.menu.ListMenuItemView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="?attr/dropdownListPreferredItemHeight"
@@ -58,4 +58,4 @@
 
     <!-- Checkbox, and/or radio button will be inserted here. -->
 
-</android.support.v7.internal.view.menu.ListMenuItemView>
+</android.support.v7.view.menu.ListMenuItemView>
diff --git a/v7/appcompat/res/layout/abc_screen_content_include.xml b/v7/appcompat/res/layout/abc_screen_content_include.xml
index 6e21f2e..1c30338 100644
--- a/v7/appcompat/res/layout/abc_screen_content_include.xml
+++ b/v7/appcompat/res/layout/abc_screen_content_include.xml
@@ -16,7 +16,7 @@
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <android.support.v7.internal.widget.ContentFrameLayout
+    <android.support.v7.widget.ContentFrameLayout
             android:id="@id/action_bar_activity_content"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
diff --git a/v7/appcompat/res/layout/abc_screen_simple.xml b/v7/appcompat/res/layout/abc_screen_simple.xml
index 426851c..2783187 100644
--- a/v7/appcompat/res/layout/abc_screen_simple.xml
+++ b/v7/appcompat/res/layout/abc_screen_simple.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.widget.FitWindowsLinearLayout
+<android.support.v7.widget.FitWindowsLinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/action_bar_root"
     android:layout_width="match_parent"
@@ -22,7 +22,7 @@
     android:orientation="vertical"
     android:fitsSystemWindows="true">
 
-    <android.support.v7.internal.widget.ViewStubCompat
+    <android.support.v7.widget.ViewStubCompat
         android:id="@+id/action_mode_bar_stub"
         android:inflatedId="@+id/action_mode_bar"
         android:layout="@layout/abc_action_mode_bar"
@@ -31,4 +31,4 @@
 
     <include layout="@layout/abc_screen_content_include" />
 
-</android.support.v7.internal.widget.FitWindowsLinearLayout>
+</android.support.v7.widget.FitWindowsLinearLayout>
diff --git a/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml b/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml
index ac399c1..c02c2aa 100644
--- a/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml
+++ b/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml
@@ -20,7 +20,7 @@
 enabled.
 -->
 
-<android.support.v7.internal.widget.FitWindowsFrameLayout
+<android.support.v7.widget.FitWindowsFrameLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/action_bar_root"
         android:layout_width="match_parent"
@@ -29,11 +29,11 @@
 
     <include layout="@layout/abc_screen_content_include" />
 
-    <android.support.v7.internal.widget.ViewStubCompat
+    <android.support.v7.widget.ViewStubCompat
             android:id="@+id/action_mode_bar_stub"
             android:inflatedId="@+id/action_mode_bar"
             android:layout="@layout/abc_action_mode_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
 
-</android.support.v7.internal.widget.FitWindowsFrameLayout>
\ No newline at end of file
+</android.support.v7.widget.FitWindowsFrameLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_screen_toolbar.xml b/v7/appcompat/res/layout/abc_screen_toolbar.xml
index 572ec34..96412c1 100644
--- a/v7/appcompat/res/layout/abc_screen_toolbar.xml
+++ b/v7/appcompat/res/layout/abc_screen_toolbar.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.widget.ActionBarOverlayLayout
+<android.support.v7.widget.ActionBarOverlayLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         android:id="@+id/decor_content_parent"
@@ -24,7 +24,7 @@
 
     <include layout="@layout/abc_screen_content_include"/>
 
-    <android.support.v7.internal.widget.ActionBarContainer
+    <android.support.v7.widget.ActionBarContainer
             android:id="@+id/action_bar_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -40,7 +40,7 @@
                 app:navigationContentDescription="@string/abc_action_bar_up_description"
                 style="?attr/toolbarStyle"/>
 
-        <android.support.v7.internal.widget.ActionBarContextView
+        <android.support.v7.widget.ActionBarContextView
                 android:id="@+id/action_context_bar"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -48,6 +48,6 @@
                 android:theme="?attr/actionBarTheme"
                 style="?attr/actionModeStyle"/>
 
-    </android.support.v7.internal.widget.ActionBarContainer>
+    </android.support.v7.widget.ActionBarContainer>
 
-</android.support.v7.internal.widget.ActionBarOverlayLayout>
+</android.support.v7.widget.ActionBarOverlayLayout>
diff --git a/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml b/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
index 7407498..b81d5d8 100644
--- a/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
+++ b/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
@@ -24,7 +24,7 @@
 
     <!-- Icons come first in the layout, since their placement doesn't depend on
          the placement of the text views. -->
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
                android:id="@android:id/icon1"
                android:layout_width="@dimen/abc_dropdownitem_icon_width"
                android:layout_height="48dip"
@@ -34,7 +34,7 @@
                android:visibility="invisible"
                style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1" />
 
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
                android:id="@+id/edit_query"
                android:layout_width="48dip"
                android:layout_height="48dip"
@@ -45,7 +45,7 @@
                android:visibility="gone"
                style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query" />
 
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
                android:id="@id/android:icon2"
                android:layout_width="48dip"
                android:layout_height="48dip"
diff --git a/v7/appcompat/res/layout/abc_search_view.xml b/v7/appcompat/res/layout/abc_search_view.xml
index ff9361dc..a7446e3 100644
--- a/v7/appcompat/res/layout/abc_search_view.xml
+++ b/v7/appcompat/res/layout/abc_search_view.xml
@@ -35,7 +35,7 @@
             android:textColor="?android:attr/textColorPrimary"
             android:visibility="gone" />
 
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
             android:id="@+id/search_button"
             style="?attr/actionButtonStyle"
             android:layout_width="wrap_content"
@@ -57,7 +57,7 @@
             android:orientation="horizontal"
             android:layoutDirection="locale">
 
-        <android.support.v7.internal.widget.TintImageView
+        <ImageView
                 android:id="@+id/search_mag_icon"
                 android:layout_width="@dimen/abc_dropdownitem_icon_width"
                 android:layout_height="wrap_content"
@@ -94,7 +94,7 @@
                   android:dropDownVerticalOffset="0dip"
                   android:dropDownHorizontalOffset="0dip" />
 
-            <android.support.v7.internal.widget.TintImageView
+            <ImageView
                     android:id="@+id/search_close_btn"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
@@ -113,7 +113,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent">
 
-            <android.support.v7.internal.widget.TintImageView
+            <ImageView
                     android:id="@+id/search_go_btn"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
@@ -125,7 +125,7 @@
                     android:focusable="true"
                     android:contentDescription="@string/abc_searchview_description_submit" />
 
-            <android.support.v7.internal.widget.TintImageView
+            <ImageView
                     android:id="@+id/search_voice_btn"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
diff --git a/v7/appcompat/res/layout/select_dialog_multichoice_material.xml b/v7/appcompat/res/layout/select_dialog_multichoice_material.xml
index 8f75bd3..60f3576 100644
--- a/v7/appcompat/res/layout/select_dialog_multichoice_material.xml
+++ b/v7/appcompat/res/layout/select_dialog_multichoice_material.xml
@@ -16,14 +16,18 @@
 -->
 
 <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@android:id/text1"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?attr/listPreferredItemHeightSmall"
-    android:textAppearance="?android:attr/textAppearanceMedium"
-    android:textColor="?attr/textColorAlertDialogListItem"
-    android:gravity="center_vertical"
-    android:paddingLeft="?attr/dialogPreferredPadding"
-    android:paddingRight="?attr/dialogPreferredPadding"
-    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
-    android:ellipsize="marquee" />
+                 android:id="@android:id/text1"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:minHeight="?attr/listPreferredItemHeightSmall"
+                 android:textAppearance="?android:attr/textAppearanceMedium"
+                 android:textColor="?attr/textColorAlertDialogListItem"
+                 android:gravity="center_vertical"
+                 android:paddingLeft="@dimen/abc_select_dialog_padding_start_material"
+                 android:paddingRight="?attr/dialogPreferredPadding"
+                 android:paddingStart="@dimen/abc_select_dialog_padding_start_material"
+                 android:paddingEnd="?attr/dialogPreferredPadding"
+                 android:drawableLeft="?android:attr/listChoiceIndicatorMultiple"
+                 android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
+                 android:drawablePadding="20dp"
+                 android:ellipsize="marquee" />
diff --git a/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml b/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml
index 3c2264c..4d10fc7 100644
--- a/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml
+++ b/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml
@@ -16,14 +16,18 @@
 -->
 
 <CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@android:id/text1"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?attr/listPreferredItemHeightSmall"
-    android:textAppearance="?android:attr/textAppearanceMedium"
-    android:textColor="?attr/textColorAlertDialogListItem"
-    android:gravity="center_vertical"
-    android:paddingLeft="?attr/dialogPreferredPadding"
-    android:paddingRight="?attr/dialogPreferredPadding"
-    android:checkMark="?android:attr/listChoiceIndicatorSingle"
-    android:ellipsize="marquee" />
+                 android:id="@android:id/text1"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:minHeight="?attr/listPreferredItemHeightSmall"
+                 android:textAppearance="?android:attr/textAppearanceMedium"
+                 android:textColor="?attr/textColorAlertDialogListItem"
+                 android:gravity="center_vertical"
+                 android:paddingLeft="@dimen/abc_select_dialog_padding_start_material"
+                 android:paddingRight="?attr/dialogPreferredPadding"
+                 android:paddingStart="@dimen/abc_select_dialog_padding_start_material"
+                 android:paddingEnd="?attr/dialogPreferredPadding"
+                 android:drawableLeft="?android:attr/listChoiceIndicatorSingle"
+                 android:drawableStart="?android:attr/listChoiceIndicatorSingle"
+                 android:drawablePadding="20dp"
+                 android:ellipsize="marquee" />
diff --git a/v7/appcompat/res/values-af/strings.xml b/v7/appcompat/res/values-af/strings.xml
index 4bb50b0..39649091 100644
--- a/v7/appcompat/res/values-af/strings.xml
+++ b/v7/appcompat/res/values-af/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deel met %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deel met"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"AAN"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"AF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-am/strings.xml b/v7/appcompat/res/values-am/strings.xml
index a76c931..ae720f8 100644
--- a/v7/appcompat/res/values-am/strings.xml
+++ b/v7/appcompat/res/values-am/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ከ%s ጋር ያጋሩ"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ከሚከተለው ጋር ያጋሩ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"በርቷል"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ጠፍቷል"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ar/strings.xml b/v7/appcompat/res/values-ar/strings.xml
index f0046a9..313daf8 100644
--- a/v7/appcompat/res/values-ar/strings.xml
+++ b/v7/appcompat/res/values-ar/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"‏مشاركة مع %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"مشاركة مع"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"تشغيل"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"إيقاف"</string>
 </resources>
diff --git a/v7/appcompat/res/values-az-rAZ/strings.xml b/v7/appcompat/res/values-az-rAZ/strings.xml
index a39f5f4..37d2399 100644
--- a/v7/appcompat/res/values-az-rAZ/strings.xml
+++ b/v7/appcompat/res/values-az-rAZ/strings.xml
@@ -36,4 +36,6 @@
     <skip />
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bununla paylaşın"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"AKTİV"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DEAKTİV"</string>
 </resources>
diff --git a/v7/appcompat/res/values-bg/strings.xml b/v7/appcompat/res/values-bg/strings.xml
index d8cbcd0..c71fd6c 100644
--- a/v7/appcompat/res/values-bg/strings.xml
+++ b/v7/appcompat/res/values-bg/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Споделяне със: %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Споделяне със:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛ."</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ИЗКЛ."</string>
 </resources>
diff --git a/v7/appcompat/res/values-bn-rBD/strings.xml b/v7/appcompat/res/values-bn-rBD/strings.xml
index 872d425..6be164f 100644
--- a/v7/appcompat/res/values-bn-rBD/strings.xml
+++ b/v7/appcompat/res/values-bn-rBD/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s এর সাথে ভাগ করুন"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"এর সাথে ভাগ করুন"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"৯৯৯+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"চালু"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"বন্ধ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ca/strings.xml b/v7/appcompat/res/values-ca/strings.xml
index 863e69f..2613ea6 100644
--- a/v7/appcompat/res/values-ca/strings.xml
+++ b/v7/appcompat/res/values-ca/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Comparteix amb %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Comparteix amb"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAT"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAT"</string>
 </resources>
diff --git a/v7/appcompat/res/values-cs/strings.xml b/v7/appcompat/res/values-cs/strings.xml
index cba91eb..c8e1921 100644
--- a/v7/appcompat/res/values-cs/strings.xml
+++ b/v7/appcompat/res/values-cs/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Sdílet pomocí %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Sdílet pomocí"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ZAPNUTO"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"VYPNUTO"</string>
 </resources>
diff --git a/v7/appcompat/res/values-da/strings.xml b/v7/appcompat/res/values-da/strings.xml
index bda45791..e7ac13f 100644
--- a/v7/appcompat/res/values-da/strings.xml
+++ b/v7/appcompat/res/values-da/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Del med %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Del med"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"TIL"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"FRA"</string>
 </resources>
diff --git a/v7/appcompat/res/values-de/strings.xml b/v7/appcompat/res/values-de/strings.xml
index b5a74e9..06a18b5 100644
--- a/v7/appcompat/res/values-de/strings.xml
+++ b/v7/appcompat/res/values-de/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Freigeben für %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Freigeben für"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"An"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"Aus"</string>
 </resources>
diff --git a/v7/appcompat/res/values-el/strings.xml b/v7/appcompat/res/values-el/strings.xml
index 1ecc119..5309082 100644
--- a/v7/appcompat/res/values-el/strings.xml
+++ b/v7/appcompat/res/values-el/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Κοινή χρήση με %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Κοινή χρήση με"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ΑΠΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rAU/strings.xml b/v7/appcompat/res/values-en-rAU/strings.xml
index 4db58a9..ab73cfd 100644
--- a/v7/appcompat/res/values-en-rAU/strings.xml
+++ b/v7/appcompat/res/values-en-rAU/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rGB/strings.xml b/v7/appcompat/res/values-en-rGB/strings.xml
index 4db58a9..ab73cfd 100644
--- a/v7/appcompat/res/values-en-rGB/strings.xml
+++ b/v7/appcompat/res/values-en-rGB/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rIN/strings.xml b/v7/appcompat/res/values-en-rIN/strings.xml
index 4db58a9..ab73cfd 100644
--- a/v7/appcompat/res/values-en-rIN/strings.xml
+++ b/v7/appcompat/res/values-en-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-es-rUS/strings.xml b/v7/appcompat/res/values-es-rUS/strings.xml
index 043c6ae..f1e3dbb 100644
--- a/v7/appcompat/res/values-es-rUS/strings.xml
+++ b/v7/appcompat/res/values-es-rUS/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAR"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAR"</string>
 </resources>
diff --git a/v7/appcompat/res/values-es/strings.xml b/v7/appcompat/res/values-es/strings.xml
index 8f6ea4b..d8e7d39 100644
--- a/v7/appcompat/res/values-es/strings.xml
+++ b/v7/appcompat/res/values-es/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"SÍ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"NO"</string>
 </resources>
diff --git a/v7/appcompat/res/values-et-rEE/strings.xml b/v7/appcompat/res/values-et-rEE/strings.xml
index b8c7f16..03091c4 100644
--- a/v7/appcompat/res/values-et-rEE/strings.xml
+++ b/v7/appcompat/res/values-et-rEE/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Jagamine kasutajaga %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Jagamine:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"SEES"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"VÄLJAS"</string>
 </resources>
diff --git a/v7/appcompat/res/values-eu-rES/strings.xml b/v7/appcompat/res/values-eu-rES/strings.xml
index 3b0fb90..92bda4a 100644
--- a/v7/appcompat/res/values-eu-rES/strings.xml
+++ b/v7/appcompat/res/values-eu-rES/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partekatu %s erabiltzailearekin"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partekatu hauekin"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"AKTIBATUTA"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DESAKTIBATUTA"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fa/strings.xml b/v7/appcompat/res/values-fa/strings.xml
index 28c76b4..97d6ea7 100644
--- a/v7/appcompat/res/values-fa/strings.xml
+++ b/v7/appcompat/res/values-fa/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"‏اشتراک‌گذاری با %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"اشتراک‌گذاری با"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"۹۹۹+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"روشن"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"خاموش"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fi/strings.xml b/v7/appcompat/res/values-fi/strings.xml
index 4b3e728..77a4a98 100644
--- a/v7/appcompat/res/values-fi/strings.xml
+++ b/v7/appcompat/res/values-fi/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Jakaminen: %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Jakaminen:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"KÄYTÖSSÄ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"POIS KÄYTÖSTÄ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fr-rCA/strings.xml b/v7/appcompat/res/values-fr-rCA/strings.xml
index 291bd4e..1f636fb 100644
--- a/v7/appcompat/res/values-fr-rCA/strings.xml
+++ b/v7/appcompat/res/values-fr-rCA/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partager avec %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partager"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVÉ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DÉSACTIVÉ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fr/strings.xml b/v7/appcompat/res/values-fr/strings.xml
index b7f5604..8fc4240 100644
--- a/v7/appcompat/res/values-fr/strings.xml
+++ b/v7/appcompat/res/values-fr/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partager avec %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partager avec"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVÉ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DÉSACTIVÉ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-gl-rES/strings.xml b/v7/appcompat/res/values-gl-rES/strings.xml
index b6b11be..ee1e7d5 100644
--- a/v7/appcompat/res/values-gl-rES/strings.xml
+++ b/v7/appcompat/res/values-gl-rES/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAR"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAR"</string>
 </resources>
diff --git a/v7/appcompat/res/values-gu-rIN/strings.xml b/v7/appcompat/res/values-gu-rIN/strings.xml
index b77acd3..6fea9bb 100644
--- a/v7/appcompat/res/values-gu-rIN/strings.xml
+++ b/v7/appcompat/res/values-gu-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s સાથે શેર કરો"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"આની સાથે શેર કરો"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ચાલુ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"બંધ"</string>
 </resources>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/appcompat/res/values-h320dp/bools.xml
similarity index 75%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v7/appcompat/res/values-h320dp/bools.xml
index a4614f6..5576c18 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/appcompat/res/values-h320dp/bools.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_setting_light" />
-</selector>
+<resources>
+    <bool name="abc_allow_stacked_button_bar">true</bool>
+</resources>
diff --git a/v7/appcompat/res/values-hi/strings.xml b/v7/appcompat/res/values-hi/strings.xml
index 95daa34..17d3d7b 100644
--- a/v7/appcompat/res/values-hi/strings.xml
+++ b/v7/appcompat/res/values-hi/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s के साथ साझा करें"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"इसके द्वारा साझा करें"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hr/strings.xml b/v7/appcompat/res/values-hr/strings.xml
index da68332..6467bfa 100644
--- a/v7/appcompat/res/values-hr/strings.xml
+++ b/v7/appcompat/res/values-hr/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Dijeljenje sa: %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Dijeljenje sa"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"UKLJUČENO"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ISKLJUČENO"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hu/strings.xml b/v7/appcompat/res/values-hu/strings.xml
index 57ab85b..1cb4fe5 100644
--- a/v7/appcompat/res/values-hu/strings.xml
+++ b/v7/appcompat/res/values-hu/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Megosztás a következővel: %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Megosztás a következővel:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"BE"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"KI"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hy-rAM/strings.xml b/v7/appcompat/res/values-hy-rAM/strings.xml
index 903fa43..708275a 100644
--- a/v7/appcompat/res/values-hy-rAM/strings.xml
+++ b/v7/appcompat/res/values-hy-rAM/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Տարածել ըստ %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Տարածել"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ՄԻԱՑՎԱԾ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ԱՆՋԱՏՎԱԾ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-in/strings.xml b/v7/appcompat/res/values-in/strings.xml
index 0e7003c..d2d0ecc 100644
--- a/v7/appcompat/res/values-in/strings.xml
+++ b/v7/appcompat/res/values-in/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Bagikan dengan %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bagikan dengan"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"AKTIF"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"NONAKTIF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-is-rIS/strings.xml b/v7/appcompat/res/values-is-rIS/strings.xml
index fb305b2..c8ded4d 100644
--- a/v7/appcompat/res/values-is-rIS/strings.xml
+++ b/v7/appcompat/res/values-is-rIS/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deila með %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deila með"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"KVEIKT"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"SLÖKKT"</string>
 </resources>
diff --git a/v7/appcompat/res/values-it/strings.xml b/v7/appcompat/res/values-it/strings.xml
index a2d9bee..31bff55 100644
--- a/v7/appcompat/res/values-it/strings.xml
+++ b/v7/appcompat/res/values-it/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Condividi con %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Condividi con"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-iw/strings.xml b/v7/appcompat/res/values-iw/strings.xml
index 329d0ec..6b834d9 100644
--- a/v7/appcompat/res/values-iw/strings.xml
+++ b/v7/appcompat/res/values-iw/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"‏שתף עם %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"שתף עם"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"‎999+‎"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"פועל"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"כבוי"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ja/strings.xml b/v7/appcompat/res/values-ja/strings.xml
index fa55b08..45fb2c0 100644
--- a/v7/appcompat/res/values-ja/strings.xml
+++ b/v7/appcompat/res/values-ja/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%sと共有"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"共有"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ka-rGE/strings.xml b/v7/appcompat/res/values-ka-rGE/strings.xml
index b14bcb7..91c31fb 100644
--- a/v7/appcompat/res/values-ka-rGE/strings.xml
+++ b/v7/appcompat/res/values-ka-rGE/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s-თან გაზიარება"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"გაზიარება:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ჩართულია"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"გამორთულია"</string>
 </resources>
diff --git a/v7/appcompat/res/values-kk-rKZ/strings.xml b/v7/appcompat/res/values-kk-rKZ/strings.xml
index 2ce080f..81fcfa9 100644
--- a/v7/appcompat/res/values-kk-rKZ/strings.xml
+++ b/v7/appcompat/res/values-kk-rKZ/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s бөлісу"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Бөлісу"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ҚОСУЛЫ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ӨШІРУЛІ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-km-rKH/strings.xml b/v7/appcompat/res/values-km-rKH/strings.xml
index aa81b7d..ee4bcbe 100644
--- a/v7/appcompat/res/values-km-rKH/strings.xml
+++ b/v7/appcompat/res/values-km-rKH/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ចែករំលែក​ជាមួយ %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ចែករំលែក​ជាមួយ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"បើក"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"បិទ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-kn-rIN/strings.xml b/v7/appcompat/res/values-kn-rIN/strings.xml
index 7ef7572..abd409e 100644
--- a/v7/appcompat/res/values-kn-rIN/strings.xml
+++ b/v7/appcompat/res/values-kn-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ಇವರೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ಆನ್"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ಆಫ್"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ko/strings.xml b/v7/appcompat/res/values-ko/strings.xml
index 7c158f9..262f543 100644
--- a/v7/appcompat/res/values-ko/strings.xml
+++ b/v7/appcompat/res/values-ko/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s와(과) 공유"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"공유 대상"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"사용"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"사용 안함"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ky-rKG/strings.xml b/v7/appcompat/res/values-ky-rKG/strings.xml
index a758b96..3176cc6 100644
--- a/v7/appcompat/res/values-ky-rKG/strings.xml
+++ b/v7/appcompat/res/values-ky-rKG/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s аркылуу бөлүшүү"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Бөлүшүү"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"КҮЙҮК"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ӨЧҮК"</string>
 </resources>
diff --git a/v7/appcompat/res/values-large/dimens.xml b/v7/appcompat/res/values-large/dimens.xml
index de1cefc..16bb4f6 100644
--- a/v7/appcompat/res/values-large/dimens.xml
+++ b/v7/appcompat/res/values-large/dimens.xml
@@ -22,17 +22,12 @@
      showAsAction="ifRoom" items can fit. "always" items can override this. -->
     <integer name="abc_max_action_buttons">4</integer>
 
-    <!-- The platform's desired fixed width for a dialog along the major axis
-         (the screen is in landscape). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_width_major">60%</item>
-    <!-- The platform's desired fixed width for a dialog along the minor axis
-         (the screen is in portrait). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_width_minor">90%</item>
-    <!-- The platform's desired fixed height for a dialog along the major axis
-         (the screen is in portrait). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_height_major">60%</item>
-    <!-- The platform's desired fixed height for a dialog along the minor axis
-         (the screen is in landscape). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_height_minor">90%</item>
+    <item type="dimen" name="abc_dialog_fixed_width_major">60%</item>
+    <item type="dimen" name="abc_dialog_fixed_width_minor">90%</item>
+    <item type="dimen" name="abc_dialog_fixed_height_major">60%</item>
+    <item type="dimen" name="abc_dialog_fixed_height_minor">90%</item>
+
+    <item type="dimen" name="abc_dialog_min_width_major">55%</item>
+    <item type="dimen" name="abc_dialog_min_width_minor">80%</item>
 
 </resources>
diff --git a/v7/appcompat/res/values-ldltr-v21/styles_base.xml b/v7/appcompat/res/values-ldltr-v21/styles_base.xml
new file mode 100644
index 0000000..57ebdba
--- /dev/null
+++ b/v7/appcompat/res/values-ldltr-v21/styles_base.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<resources>
+
+    <!-- Like in themes_base.xml, the namespace "*.AppCompat.Base" is used to
+     define base styles for the platform version. The "*.AppCompat"
+     variants are for direct use or use as parent styles by the app. -->
+    <eat-comment/>
+
+    <!-- The platform Underlined style only works in LTR in v21-22 -->
+    <style name="Base.Widget.AppCompat.Spinner.Underlined" parent="android:Widget.Material.Spinner.Underlined" />
+
+</resources>
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v7/appcompat/res/values-ldrtl-v23/styles_base.xml
similarity index 80%
rename from v17/leanback/res/layout/lb_card_color_overlay.xml
rename to v7/appcompat/res/values-ldrtl-v23/styles_base.xml
index 45a40e1..cba56bd 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v7/appcompat/res/values-ldrtl-v23/styles_base.xml
@@ -15,7 +15,8 @@
      limitations under the License.
 -->
 
-<View
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent" />
+<resources>
+
+    <style name="Base.Widget.AppCompat.Spinner.Underlined" parent="android:Widget.Material.Spinner.Underlined" />
+
+</resources>
diff --git a/v7/appcompat/res/values-lo-rLA/strings.xml b/v7/appcompat/res/values-lo-rLA/strings.xml
index 3b93232..c95fd60 100644
--- a/v7/appcompat/res/values-lo-rLA/strings.xml
+++ b/v7/appcompat/res/values-lo-rLA/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ແບ່ງ​ປັນ​ກັບ​ %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ແບ່ງປັນກັບ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ເປີດ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ປິດ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-lt/strings.xml b/v7/appcompat/res/values-lt/strings.xml
index b070a2f..992910c 100644
--- a/v7/appcompat/res/values-lt/strings.xml
+++ b/v7/appcompat/res/values-lt/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Bendrinti naudojant „%s“"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bendrinti naudojant"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ĮJUNGTI"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"IŠJUNGTI"</string>
 </resources>
diff --git a/v7/appcompat/res/values-lv/strings.xml b/v7/appcompat/res/values-lv/strings.xml
index 7c4ef4f..6700c87 100644
--- a/v7/appcompat/res/values-lv/strings.xml
+++ b/v7/appcompat/res/values-lv/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Kopīgot ar %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Kopīgot ar:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"IESLĒGTS"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"IZSLĒGTS"</string>
 </resources>
diff --git a/v7/appcompat/res/values-mk-rMK/strings.xml b/v7/appcompat/res/values-mk-rMK/strings.xml
index ac2b03e..a386996 100644
--- a/v7/appcompat/res/values-mk-rMK/strings.xml
+++ b/v7/appcompat/res/values-mk-rMK/strings.xml
@@ -38,4 +38,6 @@
     <skip />
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Сподели со"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛУЧЕНО"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ИСКЛУЧЕНО"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ml-rIN/strings.xml b/v7/appcompat/res/values-ml-rIN/strings.xml
index 53f8e4b..292fcc0 100644
--- a/v7/appcompat/res/values-ml-rIN/strings.xml
+++ b/v7/appcompat/res/values-ml-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s എന്നതുമായി പങ്കിടുക"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ഇവരുമായി പങ്കിടുക"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ഓൺ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ഓഫ്"</string>
 </resources>
diff --git a/v7/appcompat/res/values-mn-rMN/strings.xml b/v7/appcompat/res/values-mn-rMN/strings.xml
index a89dc4d..75a9724 100644
--- a/v7/appcompat/res/values-mn-rMN/strings.xml
+++ b/v7/appcompat/res/values-mn-rMN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s-тай хуваалцах"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Хуваалцах"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ИДЭВХТЭЙ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ИДЭВХГҮЙ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-mr-rIN/strings.xml b/v7/appcompat/res/values-mr-rIN/strings.xml
index 1afbd81..76d42a9 100644
--- a/v7/appcompat/res/values-mr-rIN/strings.xml
+++ b/v7/appcompat/res/values-mr-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s सह सामायिक करा"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"यांच्यासह सामायिक करा"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ms-rMY/strings.xml b/v7/appcompat/res/values-ms-rMY/strings.xml
index 9763618..75ffefb 100644
--- a/v7/appcompat/res/values-ms-rMY/strings.xml
+++ b/v7/appcompat/res/values-ms-rMY/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Kongsi dengan %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Kongsi dengan"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"HIDUP"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"MATI"</string>
 </resources>
diff --git a/v7/appcompat/res/values-my-rMM/strings.xml b/v7/appcompat/res/values-my-rMM/strings.xml
index 936ac99..f8690aa 100644
--- a/v7/appcompat/res/values-my-rMM/strings.xml
+++ b/v7/appcompat/res/values-my-rMM/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ကို မျှဝေပါရန်"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"မျှဝေဖို့ ရွေးပါ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"၉၉၉+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ဖွင့်"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ပိတ်"</string>
 </resources>
diff --git a/v7/appcompat/res/values-nb/strings.xml b/v7/appcompat/res/values-nb/strings.xml
index 483f7077..10f3024 100644
--- a/v7/appcompat/res/values-nb/strings.xml
+++ b/v7/appcompat/res/values-nb/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Del med %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Del med"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"PÅ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"AV"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ne-rNP/strings.xml b/v7/appcompat/res/values-ne-rNP/strings.xml
index 4a08778..a841f21 100644
--- a/v7/appcompat/res/values-ne-rNP/strings.xml
+++ b/v7/appcompat/res/values-ne-rNP/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s सँग साझेदारी गर्नुहोस्"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"साझेदारी गर्नुहोस्..."</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"९९९+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"सक्रिय गर्नुहोस्"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"निष्क्रिय पार्नुहोस्"</string>
 </resources>
diff --git a/v7/appcompat/res/values-nl/strings.xml b/v7/appcompat/res/values-nl/strings.xml
index 38a7607..adb0f0e 100644
--- a/v7/appcompat/res/values-nl/strings.xml
+++ b/v7/appcompat/res/values-nl/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Delen met %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Delen met"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"AAN"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"UIT"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pa-rIN/strings.xml b/v7/appcompat/res/values-pa-rIN/strings.xml
index af87fdf..45b703a 100644
--- a/v7/appcompat/res/values-pa-rIN/strings.xml
+++ b/v7/appcompat/res/values-pa-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ਇਸ ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ਤੇ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ਬੰਦ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pl/strings.xml b/v7/appcompat/res/values-pl/strings.xml
index 72fa439..166986a 100644
--- a/v7/appcompat/res/values-pl/strings.xml
+++ b/v7/appcompat/res/values-pl/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Udostępnij dla %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Udostępnij dla"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"WŁ."</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"WYŁ."</string>
 </resources>
diff --git a/v7/appcompat/res/values-pt-rBR/strings.xml b/v7/appcompat/res/values-pt-rBR/strings.xml
index dfcfce8..06cf8d9 100644
--- a/v7/appcompat/res/values-pt-rBR/strings.xml
+++ b/v7/appcompat/res/values-pt-rBR/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartilhar com %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartilhar com"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ATIVAR"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DESATIVAR"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pt-rPT/strings.xml b/v7/appcompat/res/values-pt-rPT/strings.xml
index d76c5c8..176aade 100644
--- a/v7/appcompat/res/values-pt-rPT/strings.xml
+++ b/v7/appcompat/res/values-pt-rPT/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partilhar com %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partilhar com"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ATIVADO"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DESATIVADO"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pt/strings.xml b/v7/appcompat/res/values-pt/strings.xml
index dfcfce8..06cf8d9 100644
--- a/v7/appcompat/res/values-pt/strings.xml
+++ b/v7/appcompat/res/values-pt/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartilhar com %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartilhar com"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ATIVAR"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DESATIVAR"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ro/strings.xml b/v7/appcompat/res/values-ro/strings.xml
index 55538ee..9879823 100644
--- a/v7/appcompat/res/values-ro/strings.xml
+++ b/v7/appcompat/res/values-ro/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Trimiteți la %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Trimiteți la"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"˃999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAȚI"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"DEZACTIVAȚI"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ru/strings.xml b/v7/appcompat/res/values-ru/strings.xml
index 03a2c8f..08ed085 100644
--- a/v7/appcompat/res/values-ru/strings.xml
+++ b/v7/appcompat/res/values-ru/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Открыть доступ пользователю %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Открыть доступ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛ."</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ОТКЛ."</string>
 </resources>
diff --git a/v7/appcompat/res/values-si-rLK/strings.xml b/v7/appcompat/res/values-si-rLK/strings.xml
index a03b5bd..47d7dc6 100644
--- a/v7/appcompat/res/values-si-rLK/strings.xml
+++ b/v7/appcompat/res/values-si-rLK/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s සමඟ බෙදාගන්න"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"සමඟ බෙදාගන්න"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ක්‍රියාත්මකයි"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ක්‍රියාවිරහිතයි"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sk/strings.xml b/v7/appcompat/res/values-sk/strings.xml
index f7f0b81..b7a2dc0 100644
--- a/v7/appcompat/res/values-sk/strings.xml
+++ b/v7/appcompat/res/values-sk/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Zdieľať pomocou %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Zdieľať pomocou"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ZAP."</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"VYP."</string>
 </resources>
diff --git a/v7/appcompat/res/values-sl/strings.xml b/v7/appcompat/res/values-sl/strings.xml
index 7d5f0bf..173180f 100644
--- a/v7/appcompat/res/values-sl/strings.xml
+++ b/v7/appcompat/res/values-sl/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deljenje z:"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deljenje z"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"VKLOPLJENO"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"IZKLOPLJENO"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sq-rAL/strings.xml b/v7/appcompat/res/values-sq-rAL/strings.xml
index 68689a6..758d941 100644
--- a/v7/appcompat/res/values-sq-rAL/strings.xml
+++ b/v7/appcompat/res/values-sq-rAL/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Shpërnda publikisht me %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Shpërnda publikisht me"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"AKTIV"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"JOAKTIV"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sr/strings.xml b/v7/appcompat/res/values-sr/strings.xml
index e147d75..a54af9b 100644
--- a/v7/appcompat/res/values-sr/strings.xml
+++ b/v7/appcompat/res/values-sr/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Дели са апликацијом %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Дели са"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"УКЉУЧИ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ИСКЉУЧИ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sv/strings.xml b/v7/appcompat/res/values-sv/strings.xml
index feebdb2ba..a0c9cc0 100644
--- a/v7/appcompat/res/values-sv/strings.xml
+++ b/v7/appcompat/res/values-sv/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Dela med %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Dela med"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"&gt;999"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"PÅ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"AV"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sw/strings.xml b/v7/appcompat/res/values-sw/strings.xml
index 25c4039..f1382ba 100644
--- a/v7/appcompat/res/values-sw/strings.xml
+++ b/v7/appcompat/res/values-sw/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Shiriki na %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Shiriki na:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"IMEWASHWA"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"IMEZIMWA"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ta-rIN/strings.xml b/v7/appcompat/res/values-ta-rIN/strings.xml
index 099526b..a31eb25 100644
--- a/v7/appcompat/res/values-ta-rIN/strings.xml
+++ b/v7/appcompat/res/values-ta-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s உடன் பகிர்"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"இதனுடன் பகிர்"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"இயக்கு"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"முடக்கு"</string>
 </resources>
diff --git a/v7/appcompat/res/values-te-rIN/strings.xml b/v7/appcompat/res/values-te-rIN/strings.xml
index 8ea231a4..2f6695d 100644
--- a/v7/appcompat/res/values-te-rIN/strings.xml
+++ b/v7/appcompat/res/values-te-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%sతో భాగస్వామ్యం చేయి"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"వీరితో భాగస్వామ్యం చేయి"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"ఆన్ చేయి"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ఆఫ్ చేయి"</string>
 </resources>
diff --git a/v7/appcompat/res/values-th/strings.xml b/v7/appcompat/res/values-th/strings.xml
index cc5ab0a..b77ee55 100644
--- a/v7/appcompat/res/values-th/strings.xml
+++ b/v7/appcompat/res/values-th/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"แชร์กับ %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"แชร์กับ"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"เปิด"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ปิด"</string>
 </resources>
diff --git a/v7/appcompat/res/values-tl/strings.xml b/v7/appcompat/res/values-tl/strings.xml
index aa7169f..73e1b2f 100644
--- a/v7/appcompat/res/values-tl/strings.xml
+++ b/v7/appcompat/res/values-tl/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Ibahagi sa/kay %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Ibahagi sa/kay"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"I-ON"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"I-OFF"</string>
 </resources>
diff --git a/v7/appcompat/res/values-tr/strings.xml b/v7/appcompat/res/values-tr/strings.xml
index b111b6a..56aecf6 100644
--- a/v7/appcompat/res/values-tr/strings.xml
+++ b/v7/appcompat/res/values-tr/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="abc_action_mode_done" msgid="4076576682505996667">"Bitti"</string>
+    <string name="abc_action_mode_done" msgid="4076576682505996667">"Tamamlandı"</string>
     <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Ana ekrana git"</string>
     <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Yukarı git"</string>
     <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Diğer seçenekler"</string>
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ile paylaş"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Şununla paylaş"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"AÇ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"KAPAT"</string>
 </resources>
diff --git a/v7/appcompat/res/values-uk/strings.xml b/v7/appcompat/res/values-uk/strings.xml
index ff08b47..5e81c70 100644
--- a/v7/appcompat/res/values-uk/strings.xml
+++ b/v7/appcompat/res/values-uk/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Надіслати через %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Надіслати через"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"УВІМК."</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ВИМК."</string>
 </resources>
diff --git a/v7/appcompat/res/values-ur-rPK/strings.xml b/v7/appcompat/res/values-ur-rPK/strings.xml
index 5196476..7972fe6 100644
--- a/v7/appcompat/res/values-ur-rPK/strings.xml
+++ b/v7/appcompat/res/values-ur-rPK/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"‏%s کے ساتھ اشتراک کریں"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"اشتراک کریں مع"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"‎999+‎"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"آن"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"آف"</string>
 </resources>
diff --git a/v7/appcompat/res/values-uz-rUZ/strings.xml b/v7/appcompat/res/values-uz-rUZ/strings.xml
index aa222b6..4a713a9 100644
--- a/v7/appcompat/res/values-uz-rUZ/strings.xml
+++ b/v7/appcompat/res/values-uz-rUZ/strings.xml
@@ -36,4 +36,6 @@
     <skip />
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bo‘lishish:"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"YONIQ"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"O‘CHIQ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-v17/styles_rtl.xml b/v7/appcompat/res/values-v17/styles_rtl.xml
index 85d1bd4..b3753b7 100644
--- a/v7/appcompat/res/values-v17/styles_rtl.xml
+++ b/v7/appcompat/res/values-v17/styles_rtl.xml
@@ -47,7 +47,12 @@
         <item name="android:paddingEnd">8dp</item>
     </style>
 
-    <style name="RtlOverlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton.Overflow">
+    <style name="RtlUnderlay.Widget.AppCompat.ActionButton" parent="android:Widget">
+        <item name="android:paddingStart">12dp</item>
+        <item name="android:paddingEnd">12dp</item>
+    </style>
+
+    <style name="RtlUnderlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton">
         <item name="android:paddingStart">@dimen/abc_action_bar_overflow_padding_start_material</item>
         <item name="android:paddingEnd">@dimen/abc_action_bar_overflow_padding_end_material</item>
     </style>
@@ -73,4 +78,4 @@
         <item name="android:textAlignment">viewStart</item>
     </style>
 
-</resources>
\ No newline at end of file
+</resources>
diff --git a/v7/appcompat/res/values-v21/styles_base.xml b/v7/appcompat/res/values-v21/styles_base.xml
index 47681f2..bf21d77 100644
--- a/v7/appcompat/res/values-v21/styles_base.xml
+++ b/v7/appcompat/res/values-v21/styles_base.xml
@@ -113,7 +113,7 @@
 
     <style name="Base.Widget.AppCompat.Spinner" parent="android:Widget.Material.Spinner" />
 
-    <style name="Base.Widget.AppCompat.Spinner.Underlined" parent="android:Widget.Material.Spinner.Underlined" />
+    <!-- Base.Widget.AppCompat.Spinner.Underlined is overridden in ldltr-v21 and v23 -->
 
     <style name="Base.Widget.AppCompat.ListView" parent="android:Widget.Material.ListView" />
     <style name="Base.Widget.AppCompat.ListView.Menu" />
@@ -166,12 +166,18 @@
            parent="android:TextAppearance.Material.SearchResult.Subtitle">
     </style>
 
-    <style name="Base.Widget.AppCompat.AutoCompleteTextView" parent="android:Widget.Material.AutoCompleteTextView" />
+    <style name="Base.Widget.AppCompat.AutoCompleteTextView" parent="android:Widget.Material.AutoCompleteTextView">
+        <item name="android:background">?attr/editTextBackground</item>
+    </style>
 
-    <style name="Base.Widget.AppCompat.EditText" parent="android:Widget.Material.EditText" />
+    <style name="Base.Widget.AppCompat.EditText" parent="android:Widget.Material.EditText">
+        <item name="android:background">?attr/editTextBackground</item>
+    </style>
 
     <style name="Base.Widget.AppCompat.RatingBar" parent="android:Widget.Material.RatingBar" />
 
+    <style name="Base.Widget.AppCompat.SeekBar" parent="android:Widget.Material.SeekBar" />
+
     <style name="Base.Widget.AppCompat.Button" parent="android:Widget.Material.Button" />
 
     <style name="Base.Widget.AppCompat.Button.Small" parent="android:Widget.Material.Button.Small" />
@@ -186,6 +192,8 @@
 
     <style name="Base.Widget.AppCompat.CompoundButton.RadioButton" parent="android:Widget.Material.CompoundButton.RadioButton" />
 
+    <style name="Base.Widget.AppCompat.ImageButton" parent="android:Widget.Material.ImageButton" />
+
     <!-- Progress Bar -->
 
     <style name="Base.Widget.AppCompat.ProgressBar.Horizontal"
diff --git a/v7/appcompat/res/values-v21/themes_base.xml b/v7/appcompat/res/values-v21/themes_base.xml
index 9d193d5..6c2aa26 100644
--- a/v7/appcompat/res/values-v21/themes_base.xml
+++ b/v7/appcompat/res/values-v21/themes_base.xml
@@ -48,8 +48,6 @@
         <item name="actionBarDivider">?android:attr/actionBarDivider</item>
         <item name="actionBarItemBackground">@drawable/abc_action_bar_item_background_material</item>
         <item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
-        <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
-        <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
         <item name="actionModeBackground">?android:attr/actionModeBackground</item>
         <item name="actionModeCloseDrawable">?android:attr/actionModeCloseDrawable</item>
         <item name="actionOverflowButtonStyle">?android:attr/actionOverflowButtonStyle</item>
@@ -71,12 +69,10 @@
         <item name="listChoiceBackgroundIndicator">?android:attr/listChoiceBackgroundIndicator</item>
 
         <!-- Copy the platform default styles for the AppCompat widgets -->
-        <item name="autoCompleteTextViewStyle">?android:attr/autoCompleteTextViewStyle</item>
         <item name="buttonStyle">?android:attr/buttonStyle</item>
         <item name="buttonStyleSmall">?android:attr/buttonStyleSmall</item>
         <item name="checkboxStyle">?android:attr/checkboxStyle</item>
         <item name="checkedTextViewStyle">?android:attr/checkedTextViewStyle</item>
-        <item name="editTextStyle">?android:attr/editTextStyle</item>
         <item name="radioButtonStyle">?android:attr/radioButtonStyle</item>
         <item name="ratingBarStyle">?android:attr/ratingBarStyle</item>
         <item name="spinnerStyle">?android:attr/spinnerStyle</item>
@@ -97,8 +93,6 @@
         <item name="actionBarDivider">?android:attr/actionBarDivider</item>
         <item name="actionBarItemBackground">@drawable/abc_action_bar_item_background_material</item>
         <item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
-        <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
-        <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
         <item name="actionModeBackground">?android:attr/actionModeBackground</item>
         <item name="actionModeCloseDrawable">?android:attr/actionModeCloseDrawable</item>
         <item name="actionOverflowButtonStyle">?android:attr/actionOverflowButtonStyle</item>
@@ -120,12 +114,10 @@
         <item name="listChoiceBackgroundIndicator">?android:attr/listChoiceBackgroundIndicator</item>
 
         <!-- Copy the platform default styles for the AppCompat widgets -->
-        <item name="autoCompleteTextViewStyle">?android:attr/autoCompleteTextViewStyle</item>
         <item name="buttonStyle">?android:attr/buttonStyle</item>
         <item name="buttonStyleSmall">?android:attr/buttonStyleSmall</item>
         <item name="checkboxStyle">?android:attr/checkboxStyle</item>
         <item name="checkedTextViewStyle">?android:attr/checkedTextViewStyle</item>
-        <item name="editTextStyle">?android:attr/editTextStyle</item>
         <item name="radioButtonStyle">?android:attr/radioButtonStyle</item>
         <item name="ratingBarStyle">?android:attr/ratingBarStyle</item>
         <item name="spinnerStyle">?android:attr/spinnerStyle</item>
diff --git a/v7/appcompat/res/values-v23/themes_base.xml b/v7/appcompat/res/values-v23/themes_base.xml
index becb1f2..276a3c6 100644
--- a/v7/appcompat/res/values-v23/themes_base.xml
+++ b/v7/appcompat/res/values-v23/themes_base.xml
@@ -23,6 +23,9 @@
     <style name="Base.V23.Theme.AppCompat" parent="Base.V22.Theme.AppCompat">
         <!-- We can use the platform drawable on v23+ -->
         <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+        <!-- We can use the platform styles on v23+ -->
+        <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
+        <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
 
         <item name="controlBackground">@drawable/abc_control_background_material</item>
     </style>
@@ -30,6 +33,9 @@
     <style name="Base.V23.Theme.AppCompat.Light" parent="Base.V22.Theme.AppCompat.Light">
         <!-- We can use the platform drawable on v23+ -->
         <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+        <!-- We can use the platform styles on v23+ -->
+        <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
+        <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
 
         <item name="controlBackground">@drawable/abc_control_background_material</item>
     </style>
diff --git a/v7/appcompat/res/values-vi/strings.xml b/v7/appcompat/res/values-vi/strings.xml
index 8190bc0..ec24827 100644
--- a/v7/appcompat/res/values-vi/strings.xml
+++ b/v7/appcompat/res/values-vi/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Chia sẻ với %s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Chia sẻ với"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"BẬT"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"TẮT"</string>
 </resources>
diff --git a/v7/appcompat/res/values-xlarge/dimens.xml b/v7/appcompat/res/values-xlarge/dimens.xml
index 3eb2962..0dd244a 100644
--- a/v7/appcompat/res/values-xlarge/dimens.xml
+++ b/v7/appcompat/res/values-xlarge/dimens.xml
@@ -24,17 +24,12 @@
     <!-- Minimum width of the search view text entry area. -->
     <dimen name="abc_search_view_text_min_width">192dip</dimen>
 
-    <!-- The platform's desired fixed width for a dialog along the major axis
-         (the screen is in landscape). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_width_major">50%</item>
-    <!-- The platform's desired fixed width for a dialog along the minor axis
-         (the screen is in portrait). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_width_minor">70%</item>
-    <!-- The platform's desired fixed height for a dialog along the major axis
-         (the screen is in portrait). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_height_major">60%</item>
-    <!-- The platform's desired fixed height for a dialog along the minor axis
-         (the screen is in landscape). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_height_minor">90%</item>
+    <item type="dimen" name="abc_dialog_fixed_width_major">50%</item>
+    <item type="dimen" name="abc_dialog_fixed_width_minor">70%</item>
+    <item type="dimen" name="abc_dialog_fixed_height_major">60%</item>
+    <item type="dimen" name="abc_dialog_fixed_height_minor">90%</item>
+
+    <item type="dimen" name="abc_dialog_min_width_major">45%</item>
+    <item type="dimen" name="abc_dialog_min_width_minor">72%</item>
 
 </resources>
diff --git a/v7/appcompat/res/values-zh-rCN/strings.xml b/v7/appcompat/res/values-zh-rCN/strings.xml
index b0fbc2f..8ac28b7 100644
--- a/v7/appcompat/res/values-zh-rCN/strings.xml
+++ b/v7/appcompat/res/values-zh-rCN/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"通过%s分享"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"分享方式"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"开启"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"关闭"</string>
 </resources>
diff --git a/v7/appcompat/res/values-zh-rHK/strings.xml b/v7/appcompat/res/values-zh-rHK/strings.xml
index 2c46334..91d3289 100644
--- a/v7/appcompat/res/values-zh-rHK/strings.xml
+++ b/v7/appcompat/res/values-zh-rHK/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"與「%s」分享"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"分享對象"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999 +"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"開啟"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"關閉"</string>
 </resources>
diff --git a/v7/appcompat/res/values-zh-rTW/strings.xml b/v7/appcompat/res/values-zh-rTW/strings.xml
index bfabf5a..45fea16 100644
--- a/v7/appcompat/res/values-zh-rTW/strings.xml
+++ b/v7/appcompat/res/values-zh-rTW/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"與「%s」分享"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"選擇分享對象"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"開啟"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"關閉"</string>
 </resources>
diff --git a/v7/appcompat/res/values-zu/strings.xml b/v7/appcompat/res/values-zu/strings.xml
index edc265d..932624f 100644
--- a/v7/appcompat/res/values-zu/strings.xml
+++ b/v7/appcompat/res/values-zu/strings.xml
@@ -34,4 +34,6 @@
     <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Yabelana no-%s"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Yabelana no-"</string>
     <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+    <string name="abc_capital_on" msgid="3405795526292276155">"VULIWE"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"VALIWE"</string>
 </resources>
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index 040bea1..83cb1b2 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -239,6 +239,9 @@
         <!-- EditText background drawable. -->
         <attr name="editTextBackground" format="reference" />
 
+        <!-- ImageButton background drawable. -->
+        <attr name="imageButtonStyle" format="reference" />
+
         <!-- ============================ -->
         <!-- SearchView styles and assets -->
         <!-- ============================ -->
@@ -371,6 +374,8 @@
         <attr name="radioButtonStyle" format="reference" />
         <!-- Default RatingBar style. -->
         <attr name="ratingBarStyle" format="reference" />
+        <!-- Default SeekBar style. -->
+        <attr name="seekBarStyle" format="reference" />
         <!-- Default Spinner style. -->
         <attr name="spinnerStyle" format="reference" />
         <!-- Default style for the Switch widget. -->
@@ -681,6 +686,8 @@
         <attr name="android:popupBackground" />
         <!-- Width of the dropdown in spinnerMode="dropdown". -->
         <attr name="android:dropDownWidth" />
+        <!-- Reference to an array resource that will populate the Spinner. -->
+        <attr name="android:entries" />
     </declare-styleable>
 
     <declare-styleable name="SearchView">
@@ -931,6 +938,10 @@
         <attr name="android:textStyle" />
         <attr name="android:typeface" />
         <attr name="textAllCaps" />
+        <attr name="android:shadowColor"/>
+        <attr name="android:shadowDy"/>
+        <attr name="android:shadowDx"/>
+        <attr name="android:shadowRadius"/>
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -943,4 +954,11 @@
         <attr name="listItemLayout" format="reference" />
     </declare-styleable>
 
+    <!-- @hide -->
+    <declare-styleable name="ButtonBarLayout">
+        <!-- Whether to automatically stack the buttons when there is not
+             enough space to lay them out side-by-side. -->
+        <attr name="allowStacking" format="boolean" />
+    </declare-styleable>
+
 </resources>
diff --git a/v7/appcompat/res/values/bools.xml b/v7/appcompat/res/values/bools.xml
index 79a5035..3508cf3 100644
--- a/v7/appcompat/res/values/bools.xml
+++ b/v7/appcompat/res/values/bools.xml
@@ -21,4 +21,8 @@
     <bool name="abc_action_bar_expanded_action_views_exclusive">true</bool>
 
     <bool name="abc_config_showMenuShortcutsWhenKeyboardPresent">false</bool>
+
+    <!-- Whether to allow vertically stacked button bars. This is disabled for
+         configurations with a small (e.g. less than 320dp) screen height. -->
+    <bool name="abc_allow_stacked_button_bar">false</bool>
 </resources>
diff --git a/v7/appcompat/res/values/colors_material.xml b/v7/appcompat/res/values/colors_material.xml
index cf30f0dd..70fd21d 100644
--- a/v7/appcompat/res/values/colors_material.xml
+++ b/v7/appcompat/res/values/colors_material.xml
@@ -30,8 +30,8 @@
     <color name="primary_dark_material_dark">@android:color/black</color>
     <color name="primary_dark_material_light">@color/material_grey_600</color>
 
-    <!-- 26% white (foreground) -->
-    <color name="ripple_material_dark">#42ffffff</color>
+    <!-- 20% white (foreground) -->
+    <color name="ripple_material_dark">#33ffffff</color>
     <!-- 12% black (foreground) -->
     <color name="ripple_material_light">#1f000000</color>
 
diff --git a/v7/appcompat/res/values/dimens.xml b/v7/appcompat/res/values/dimens.xml
index 06f1a06..37130e3 100644
--- a/v7/appcompat/res/values/dimens.xml
+++ b/v7/appcompat/res/values/dimens.xml
@@ -44,19 +44,18 @@
     <!-- Width of the icon in a dropdown list -->
     <dimen name="abc_dropdownitem_icon_width">32dip</dimen>
 
-
     <!-- The platform's desired fixed width for a dialog along the major axis
          (the screen is in landscape). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_width_major">320dp</item>
+    <item type="dimen" name="abc_dialog_fixed_width_major">320dp</item>
     <!-- The platform's desired fixed width for a dialog along the minor axis
          (the screen is in portrait). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_width_minor">320dp</item>
+    <item type="dimen" name="abc_dialog_fixed_width_minor">320dp</item>
     <!-- The platform's desired fixed height for a dialog along the major axis
          (the screen is in portrait). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_height_major">80%</item>
+    <item type="dimen" name="abc_dialog_fixed_height_major">80%</item>
     <!-- The platform's desired fixed height for a dialog along the minor axis
          (the screen is in landscape). This may be either a fraction or a dimension.-->
-    <item type="dimen" name="dialog_fixed_height_minor">100%</item>
+    <item type="dimen" name="abc_dialog_fixed_height_minor">100%</item>
 
     <dimen name="abc_button_inset_vertical_material">6dp</dimen>
     <dimen name="abc_button_inset_horizontal_material">@dimen/abc_control_inset_material</dimen>
@@ -87,6 +86,9 @@
     <!-- Padding above and below selection dialog lists. -->
     <dimen name="abc_dialog_list_padding_vertical_material">8dp</dimen>
 
+    <!-- Dialog padding minus control padding, used to fix alignment. -->
+    <dimen name="abc_select_dialog_padding_start_material">20dp</dimen>
+
     <!-- The platform's desired minimum size for a dialog's width when it
          is along the major axis (that is the screen is landscape).  This may
          be either a fraction or a dimension. -->
diff --git a/v7/appcompat/res/values/dimens_material.xml b/v7/appcompat/res/values/dimens_material.xml
index f67127c..357dc3e 100644
--- a/v7/appcompat/res/values/dimens_material.xml
+++ b/v7/appcompat/res/values/dimens_material.xml
@@ -68,4 +68,7 @@
     <item name="abc_disabled_alpha_material_light" format="float" type="dimen">0.26</item>
     <item name="abc_disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
 
+    <dimen name="abc_seekbar_track_background_height_material">2dp</dimen>
+    <dimen name="abc_seekbar_track_progress_height_material">2dp</dimen>
+
 </resources>
diff --git a/v7/appcompat/res/values/strings.xml b/v7/appcompat/res/values/strings.xml
index a04b396..6e2a622 100644
--- a/v7/appcompat/res/values/strings.xml
+++ b/v7/appcompat/res/values/strings.xml
@@ -68,4 +68,9 @@
          for most appropriate textual indicator of "more than X".
          [CHAR LIMIT=4] -->
     <string name="status_bar_notification_info_overflow">999+</string>
+
+    <!-- Default text for a button that can be toggled on and off. -->
+    <string name="abc_capital_on">ON</string>
+    <!-- Default text for a button that can be toggled on and off. -->
+    <string name="abc_capital_off">OFF</string>
 </resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index e10c01f..6c5c776 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -60,8 +60,7 @@
 
     <style name="Widget.AppCompat.ActionButton.CloseMode" parent="Base.Widget.AppCompat.ActionButton.CloseMode" />
 
-    <style name="Widget.AppCompat.ActionButton.Overflow"
-           parent="RtlOverlay.Widget.AppCompat.ActionButton.Overflow" />
+    <style name="Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton.Overflow" />
 
     <style name="Widget.AppCompat.ActionBar.TabBar"
            parent="Base.Widget.AppCompat.ActionBar.TabBar">
@@ -218,12 +217,16 @@
 
     <style name="Widget.AppCompat.ButtonBar.AlertDialog" parent="Base.Widget.AppCompat.ButtonBar.AlertDialog" />
 
+    <style name="Widget.AppCompat.ImageButton" parent="Base.Widget.AppCompat.ImageButton" />
+
     <style name="Widget.AppCompat.TextView.SpinnerItem" parent="Base.Widget.AppCompat.TextView.SpinnerItem" />
 
     <style name="AlertDialog.AppCompat" parent="Base.AlertDialog.AppCompat" />
 
     <style name="AlertDialog.AppCompat.Light" parent="Base.AlertDialog.AppCompat.Light" />
 
+    <style name="Widget.AppCompat.SeekBar" parent="Base.Widget.AppCompat.SeekBar" />
+
     <!-- Toolbar -->
 
     <style name="Widget.AppCompat.Toolbar" parent="Base.Widget.AppCompat.Toolbar" />
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index d65b16f..b119217 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -60,10 +60,8 @@
         <item name="backgroundSplit">?attr/colorPrimary</item>
     </style>
 
-    <style name="Base.Widget.AppCompat.ActionButton" parent="">
+    <style name="Base.Widget.AppCompat.ActionButton" parent="RtlUnderlay.Widget.AppCompat.ActionButton">
         <item name="android:background">?attr/actionBarItemBackground</item>
-        <item name="android:paddingLeft">12dip</item>
-        <item name="android:paddingRight">12dip</item>
         <item name="android:minWidth">@dimen/abc_action_button_min_width_material</item>
         <item name="android:minHeight">@dimen/abc_action_button_min_height_material</item>
         <item name="android:scaleType">center</item>
@@ -76,7 +74,7 @@
         <item name="android:background">?attr/controlBackground</item>
     </style>
 
-    <style name="Base.Widget.AppCompat.ActionButton.Overflow">
+    <style name="Base.Widget.AppCompat.ActionButton.Overflow" parent="RtlUnderlay.Widget.AppCompat.ActionButton.Overflow">
         <item name="android:src">@drawable/abc_ic_menu_moreoverflow_mtrl_alpha</item>
         <item name="android:background">?attr/actionBarItemBackground</item>
         <item name="android:contentDescription">@string/abc_action_menu_overflow_description</item>
@@ -386,6 +384,8 @@
         <item name="android:background">?attr/controlBackground</item>
         <item name="showText">false</item>
         <item name="switchPadding">@dimen/abc_switch_padding</item>
+        <item name="android:textOn">@string/abc_capital_on</item>
+        <item name="android:textOff">@string/abc_capital_off</item>
     </style>
 
     <style name="Base.TextAppearance.AppCompat.Widget.Switch" parent="TextAppearance.AppCompat.Button" />
@@ -395,6 +395,16 @@
         <item name="android:indeterminateDrawable">@drawable/abc_ratingbar_full_material</item>
     </style>
 
+    <style name="Base.Widget.AppCompat.SeekBar" parent="android:Widget">
+        <item name="android:indeterminateOnly">false</item>
+        <item name="android:progressDrawable">@drawable/abc_seekbar_track_material</item>
+        <item name="android:indeterminateDrawable">@drawable/abc_seekbar_track_material</item>
+        <item name="android:thumb">@drawable/abc_seekbar_thumb_material</item>
+        <item name="android:focusable">true</item>
+        <item name="android:paddingLeft">16dip</item>
+        <item name="android:paddingRight">16dip</item>
+    </style>
+
     <!-- Bordered ink button -->
     <style name="Base.Widget.AppCompat.Button" parent="android:Widget">
         <item name="android:background">@drawable/abc_btn_default_mtrl_shape</item>
@@ -434,6 +444,10 @@
         <item name="android:minHeight">@dimen/abc_alert_dialog_button_bar_height</item>
     </style>
 
+    <style name="Base.Widget.AppCompat.ImageButton" parent="android:Widget.ImageButton">
+        <item name="android:background">@drawable/abc_btn_default_mtrl_shape</item>
+    </style>
+
     <style name="Base.Widget.AppCompat.TextView.SpinnerItem" parent="android:Widget.TextView.SpinnerItem">
         <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem</item>
         <item name="android:paddingLeft">8dp</item>
diff --git a/v7/appcompat/res/values/styles_rtl.xml b/v7/appcompat/res/values/styles_rtl.xml
index 876b396..a70aa30 100644
--- a/v7/appcompat/res/values/styles_rtl.xml
+++ b/v7/appcompat/res/values/styles_rtl.xml
@@ -47,7 +47,12 @@
         <item name="android:paddingRight">8dp</item>
     </style>
 
-    <style name="RtlOverlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton.Overflow">
+    <style name="RtlUnderlay.Widget.AppCompat.ActionButton" parent="android:Widget">
+        <item name="android:paddingLeft">12dp</item>
+        <item name="android:paddingRight">12dp</item>
+    </style>
+
+    <style name="RtlUnderlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton">
         <item name="android:paddingLeft">@dimen/abc_action_bar_overflow_padding_start_material</item>
         <item name="android:paddingRight">@dimen/abc_action_bar_overflow_padding_end_material</item>
     </style>
@@ -71,4 +76,4 @@
     <style name="RtlOverlay.DialogWindowTitle.AppCompat" parent="Base.DialogWindowTitle.AppCompat">
     </style>
 
-</resources>
\ No newline at end of file
+</resources>
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index d0dfca5..f8e0ac6 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -111,8 +111,10 @@
 
     <!-- Base platform-dependent theme providing an action bar in a dark-themed activity. -->
     <style name="Base.V7.Theme.AppCompat" parent="Platform.AppCompat">
+        <item name="windowNoTitle">false</item>
         <item name="windowActionBar">true</item>
         <item name="windowActionBarOverlay">false</item>
+        <item name="windowActionModeOverlay">false</item>
         <item name="actionBarPopupTheme">@null</item>
 
         <!-- Used by MediaRouter -->
@@ -189,7 +191,7 @@
         <item name="textAppearanceLargePopupMenu">@style/TextAppearance.AppCompat.Widget.PopupMenu.Large</item>
         <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.AppCompat.Widget.PopupMenu.Small</item>
         <item name="listPopupWindowStyle">@style/Widget.AppCompat.ListPopupWindow</item>
-        <item name="dropDownListViewStyle">@style/Widget.AppCompat.ListView.DropDown</item>
+        <item name="dropDownListViewStyle">?android:attr/dropDownListViewStyle</item>
 
         <!-- SearchView attributes -->
         <item name="searchViewStyle">@style/Widget.AppCompat.SearchView</item>
@@ -229,12 +231,15 @@
         <item name="switchStyle">@style/Widget.AppCompat.CompoundButton.Switch</item>
 
         <item name="ratingBarStyle">@style/Widget.AppCompat.RatingBar</item>
+        <item name="seekBarStyle">@style/Widget.AppCompat.SeekBar</item>
 
         <!-- Button styles -->
         <item name="buttonStyle">@style/Widget.AppCompat.Button</item>
         <item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
         <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
 
+        <item name="imageButtonStyle">@style/Widget.AppCompat.ImageButton</item>
+
         <item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
         <item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
         <item name="buttonBarPositiveButtonStyle">?attr/buttonBarButtonStyle</item>
@@ -261,8 +266,10 @@
 
     <!-- Base platform-dependent theme providing an action bar in a light-themed activity. -->
     <style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
+        <item name="windowNoTitle">false</item>
         <item name="windowActionBar">true</item>
         <item name="windowActionBarOverlay">false</item>
+        <item name="windowActionModeOverlay">false</item>
         <item name="actionBarPopupTheme">@null</item>
 
         <!-- Used by MediaRouter -->
@@ -339,7 +346,7 @@
         <item name="textAppearanceLargePopupMenu">@style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Large</item>
         <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Small</item>
         <item name="listPopupWindowStyle">@style/Widget.AppCompat.ListPopupWindow</item>
-        <item name="dropDownListViewStyle">@style/Widget.AppCompat.ListView.DropDown</item>
+        <item name="dropDownListViewStyle">?android:attr/dropDownListViewStyle</item>
 
         <!-- SearchView attributes -->
         <item name="searchViewStyle">@style/Widget.AppCompat.Light.SearchView</item>
@@ -379,12 +386,15 @@
         <item name="switchStyle">@style/Widget.AppCompat.CompoundButton.Switch</item>
 
         <item name="ratingBarStyle">@style/Widget.AppCompat.RatingBar</item>
+        <item name="seekBarStyle">@style/Widget.AppCompat.SeekBar</item>
 
         <!-- Button styles -->
         <item name="buttonStyle">@style/Widget.AppCompat.Button</item>
         <item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
         <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
 
+        <item name="imageButtonStyle">@style/Widget.AppCompat.ImageButton</item>
+
         <item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
         <item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
         <item name="buttonBarPositiveButtonStyle">?attr/buttonBarButtonStyle</item>
@@ -504,17 +514,17 @@
     </style>
 
     <style name="Base.Theme.AppCompat.Dialog.FixedSize">
-        <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
-        <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
-        <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
-        <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+        <item name="windowFixedWidthMajor">@dimen/abc_dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@dimen/abc_dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@dimen/abc_dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@dimen/abc_dialog_fixed_height_minor</item>
     </style>
 
     <style name="Base.Theme.AppCompat.Light.Dialog.FixedSize">
-        <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
-        <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
-        <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
-        <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+        <item name="windowFixedWidthMajor">@dimen/abc_dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@dimen/abc_dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@dimen/abc_dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@dimen/abc_dialog_fixed_height_minor</item>
     </style>
 
     <!-- We're not large, so redirect to Theme.AppCompat -->
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
index 6dceaf6..c15c531 100644
--- a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
+++ b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
@@ -282,9 +282,11 @@
     }
 
     private void toggle() {
-        if (mDrawerLayout.isDrawerVisible(GravityCompat.START)) {
+        int drawerLockMode = mDrawerLayout.getDrawerLockMode(GravityCompat.START);
+        if (mDrawerLayout.isDrawerVisible(GravityCompat.START)
+                && (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
             mDrawerLayout.closeDrawer(GravityCompat.START);
-        } else {
+        } else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
             mDrawerLayout.openDrawer(GravityCompat.START);
         }
     }
diff --git a/v7/appcompat/src/android/support/v7/app/AlertController.java b/v7/appcompat/src/android/support/v7/app/AlertController.java
index 76c1670..5f8eb4b 100644
--- a/v7/appcompat/src/android/support/v7/app/AlertController.java
+++ b/v7/appcompat/src/android/support/v7/app/AlertController.java
@@ -21,20 +21,25 @@
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
+import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.NestedScrollView;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintTypedArray;
 import android.text.TextUtils;
 import android.util.TypedValue;
-import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
+import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ArrayAdapter;
@@ -46,7 +51,6 @@
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
 import android.widget.ListView;
-import android.widget.ScrollView;
 import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
 
@@ -84,7 +88,7 @@
     private CharSequence mButtonNeutralText;
     private Message mButtonNeutralMessage;
 
-    private ScrollView mScrollView;
+    private NestedScrollView mScrollView;
 
     private int mIconId = 0;
     private Drawable mIcon;
@@ -159,19 +163,13 @@
         }
     }
 
-    private static boolean shouldCenterSingleButton(Context context) {
-        TypedValue outValue = new TypedValue();
-        context.getTheme().resolveAttribute(R.attr.alertDialogCenterButtons, outValue, true);
-        return outValue.data != 0;
-    }
-
     public AlertController(Context context, AppCompatDialog di, Window window) {
         mContext = context;
         mDialog = di;
         mWindow = window;
         mHandler = new ButtonHandler(di);
 
-        TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog,
+        final TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog,
                 R.attr.alertDialogStyle, 0);
 
         mAlertDialogLayout = a.getResourceId(R.styleable.AlertDialog_android_layout, 0);
@@ -211,7 +209,6 @@
     public void installContent() {
         /* We use a custom title so never request a window title */
         mDialog.supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
-
         final int contentView = selectContentView();
         mDialog.setContentView(contentView);
         setupView();
@@ -368,6 +365,7 @@
     /**
      * @param attrId the attributeId of the theme-specific drawable
      *               to resolve the resourceId for.
+     *
      * @return resId the resourceId of the theme-specific drawable
      */
     public int getIconAttributeResId(int attrId) {
@@ -403,26 +401,194 @@
         return mScrollView != null && mScrollView.executeKeyEvent(event);
     }
 
-    private void setupView() {
-        final ViewGroup contentPanel = (ViewGroup) mWindow.findViewById(R.id.contentPanel);
-        setupContent(contentPanel);
-        final boolean hasButtons = setupButtons();
+    /**
+     * Resolves whether a custom or default panel should be used. Removes the
+     * default panel if a custom panel should be used. If the resolved panel is
+     * a view stub, inflates before returning.
+     *
+     * @param customPanel the custom panel
+     * @param defaultPanel the default panel
+     * @return the panel to use
+     */
+    @Nullable
+    private ViewGroup resolvePanel(@Nullable View customPanel, @Nullable View defaultPanel) {
+        if (customPanel == null) {
+            // Inflate the default panel, if needed.
+            if (defaultPanel instanceof ViewStub) {
+                defaultPanel = ((ViewStub) defaultPanel).inflate();
+            }
 
-        final ViewGroup topPanel = (ViewGroup) mWindow.findViewById(R.id.topPanel);
-        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(mContext,
-                null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
-        final boolean hasTitle = setupTitle(topPanel);
+            return (ViewGroup) defaultPanel;
+        }
 
-        final View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
-        if (!hasButtons) {
-            buttonPanel.setVisibility(View.GONE);
-            final View spacer = mWindow.findViewById(R.id.textSpacerNoButtons);
-            if (spacer != null) {
-                spacer.setVisibility(View.VISIBLE);
+        // Remove the default panel entirely.
+        if (defaultPanel != null) {
+            final ViewParent parent = defaultPanel.getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(defaultPanel);
             }
         }
 
-        final FrameLayout customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
+        // Inflate the custom panel, if needed.
+        if (customPanel instanceof ViewStub) {
+            customPanel = ((ViewStub) customPanel).inflate();
+        }
+
+        return (ViewGroup) customPanel;
+    }
+
+    private void setupView() {
+        final View parentPanel = mWindow.findViewById(R.id.parentPanel);
+        final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
+        final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
+        final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
+
+        // Install custom content before setting up the title or buttons so
+        // that we can handle panel overrides.
+        final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
+        setupCustomContent(customPanel);
+
+        final View customTopPanel = customPanel.findViewById(R.id.topPanel);
+        final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
+        final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
+
+        // Resolve the correct panels and remove the defaults, if needed.
+        final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
+        final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
+        final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
+
+        setupContent(contentPanel);
+        setupButtons(buttonPanel);
+        setupTitle(topPanel);
+
+        final boolean hasCustomPanel = customPanel != null
+                && customPanel.getVisibility() != View.GONE;
+        final boolean hasTopPanel = topPanel != null
+                && topPanel.getVisibility() != View.GONE;
+        final boolean hasButtonPanel = buttonPanel != null
+                && buttonPanel.getVisibility() != View.GONE;
+
+        // Only display the text spacer if we don't have buttons.
+        if (!hasButtonPanel) {
+            if (contentPanel != null) {
+                final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
+                if (spacer != null) {
+                    spacer.setVisibility(View.VISIBLE);
+                }
+            }
+        }
+
+        if (hasTopPanel) {
+            // Only clip scrolling content to padding if we have a title.
+            if (mScrollView != null) {
+                mScrollView.setClipToPadding(true);
+            }
+        }
+
+        // Update scroll indicators as needed.
+        if (!hasCustomPanel) {
+            final View content = mListView != null ? mListView : mScrollView;
+            if (content != null) {
+                final int indicators = (hasTopPanel ? ViewCompat.SCROLL_INDICATOR_TOP : 0)
+                        | (hasButtonPanel ? ViewCompat.SCROLL_INDICATOR_BOTTOM : 0);
+                setScrollIndicators(contentPanel, content, indicators,
+                        ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);
+            }
+        }
+
+        final ListView listView = mListView;
+        if (listView != null && mAdapter != null) {
+            listView.setAdapter(mAdapter);
+            final int checkedItem = mCheckedItem;
+            if (checkedItem > -1) {
+                listView.setItemChecked(checkedItem, true);
+                listView.setSelection(checkedItem);
+            }
+        }
+    }
+
+    private void setScrollIndicators(ViewGroup contentPanel, View content,
+            final int indicators, final int mask) {
+        // Set up scroll indicators (if present).
+        View indicatorUp = mWindow.findViewById(R.id.scrollIndicatorUp);
+        View indicatorDown = mWindow.findViewById(R.id.scrollIndicatorDown);
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            // We're on Marshmallow so can rely on the View APIs
+            ViewCompat.setScrollIndicators(content, indicators, mask);
+            // We can also remove the compat indicator views
+            if (indicatorUp != null) {
+                contentPanel.removeView(indicatorUp);
+            }
+            if (indicatorDown != null) {
+                contentPanel.removeView(indicatorDown);
+            }
+        } else {
+            // First, remove the indicator views if we're not set to use them
+            if (indicatorUp != null && (indicators & ViewCompat.SCROLL_INDICATOR_TOP) == 0) {
+                contentPanel.removeView(indicatorUp);
+                indicatorUp = null;
+            }
+            if (indicatorDown != null && (indicators & ViewCompat.SCROLL_INDICATOR_BOTTOM) == 0) {
+                contentPanel.removeView(indicatorDown);
+                indicatorDown = null;
+            }
+
+            if (indicatorUp != null || indicatorDown != null) {
+                final View top = indicatorUp;
+                final View bottom = indicatorDown;
+
+                if (mMessage != null) {
+                    // We're just showing the ScrollView, set up listener.
+                    mScrollView.setOnScrollChangeListener(
+                            new NestedScrollView.OnScrollChangeListener() {
+                                @Override
+                                public void onScrollChange(NestedScrollView v, int scrollX,
+                                        int scrollY,
+                                        int oldScrollX, int oldScrollY) {
+                                    manageScrollIndicators(v, top, bottom);
+                                }
+                            });
+                    // Set up the indicators following layout.
+                    mScrollView.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            manageScrollIndicators(mScrollView, top, bottom);
+                        }
+                    });
+                } else if (mListView != null) {
+                    // We're just showing the AbsListView, set up listener.
+                    mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
+                        @Override
+                        public void onScrollStateChanged(AbsListView view, int scrollState) {}
+
+                        @Override
+                        public void onScroll(AbsListView v, int firstVisibleItem,
+                                int visibleItemCount, int totalItemCount) {
+                            manageScrollIndicators(v, top, bottom);
+                        }
+                    });
+                    // Set up the indicators following layout.
+                    mListView.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            manageScrollIndicators(mListView, top, bottom);
+                        }
+                    });
+                } else {
+                    // We don't have any content to scroll, remove the indicators.
+                    if (top != null) {
+                        contentPanel.removeView(top);
+                    }
+                    if (bottom != null) {
+                        contentPanel.removeView(bottom);
+                    }
+                }
+            }
+        }
+    }
+
+    private void setupCustomContent(ViewGroup customPanel) {
         final View customView;
         if (mView != null) {
             customView = mView;
@@ -454,23 +620,9 @@
         } else {
             customPanel.setVisibility(View.GONE);
         }
-
-        final ListView listView = mListView;
-        if (listView != null && mAdapter != null) {
-            listView.setAdapter(mAdapter);
-            final int checkedItem = mCheckedItem;
-            if (checkedItem > -1) {
-                listView.setItemChecked(checkedItem, true);
-                listView.setSelection(checkedItem);
-            }
-        }
-
-        a.recycle();
     }
 
-    private boolean setupTitle(ViewGroup topPanel) {
-        boolean hasTitle = true;
-
+    private void setupTitle(ViewGroup topPanel) {
         if (mCustomTitleView != null) {
             // Add the custom title view directly to the topPanel layout
             LayoutParams lp = new LayoutParams(
@@ -512,18 +664,17 @@
                 titleTemplate.setVisibility(View.GONE);
                 mIconView.setVisibility(View.GONE);
                 topPanel.setVisibility(View.GONE);
-                hasTitle = false;
             }
         }
-        return hasTitle;
     }
 
     private void setupContent(ViewGroup contentPanel) {
-        mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
+        mScrollView = (NestedScrollView) mWindow.findViewById(R.id.scrollView);
         mScrollView.setFocusable(false);
+        mScrollView.setNestedScrollingEnabled(false);
 
         // Special case for users that only want to display a String
-        mMessageView = (TextView) mWindow.findViewById(android.R.id.message);
+        mMessageView = (TextView) contentPanel.findViewById(android.R.id.message);
         if (mMessageView == null) {
             return;
         }
@@ -546,12 +697,23 @@
         }
     }
 
-    private boolean setupButtons() {
+    private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
+        if (upIndicator != null) {
+            upIndicator.setVisibility(
+                    ViewCompat.canScrollVertically(v, -1) ? View.VISIBLE : View.INVISIBLE);
+        }
+        if (downIndicator != null) {
+            downIndicator.setVisibility(
+                    ViewCompat.canScrollVertically(v, 1) ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+
+    private void setupButtons(ViewGroup buttonPanel) {
         int BIT_BUTTON_POSITIVE = 1;
         int BIT_BUTTON_NEGATIVE = 2;
         int BIT_BUTTON_NEUTRAL = 4;
         int whichButtons = 0;
-        mButtonPositive = (Button) mWindow.findViewById(android.R.id.button1);
+        mButtonPositive = (Button) buttonPanel.findViewById(android.R.id.button1);
         mButtonPositive.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonPositiveText)) {
@@ -562,7 +724,7 @@
             whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
         }
 
-        mButtonNegative = (Button) mWindow.findViewById(android.R.id.button2);
+        mButtonNegative = (Button) buttonPanel.findViewById(android.R.id.button2);
         mButtonNegative.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonNegativeText)) {
@@ -574,7 +736,7 @@
             whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
         }
 
-        mButtonNeutral = (Button) mWindow.findViewById(android.R.id.button3);
+        mButtonNeutral = (Button) buttonPanel.findViewById(android.R.id.button3);
         mButtonNeutral.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonNeutralText)) {
@@ -586,28 +748,10 @@
             whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
         }
 
-        if (shouldCenterSingleButton(mContext)) {
-            /*
-             * If we only have 1 button it should be centered on the layout and
-             * expand to fill 50% of the available space.
-             */
-            if (whichButtons == BIT_BUTTON_POSITIVE) {
-                centerButton(mButtonPositive);
-            } else if (whichButtons == BIT_BUTTON_NEGATIVE) {
-                centerButton(mButtonNegative);
-            } else if (whichButtons == BIT_BUTTON_NEUTRAL) {
-                centerButton(mButtonNeutral);
-            }
+        final boolean hasButtons = whichButtons != 0;
+        if (!hasButtons) {
+            buttonPanel.setVisibility(View.GONE);
         }
-
-        return whichButtons != 0;
-    }
-
-    private void centerButton(Button button) {
-        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) button.getLayoutParams();
-        params.gravity = Gravity.CENTER_HORIZONTAL;
-        params.weight = 0.5f;
-        button.setLayoutParams(params);
     }
 
     public static class AlertParams {
@@ -661,7 +805,6 @@
 
             /**
              * Called before the ListView is bound to an adapter.
-             *
              * @param listView The ListView that will be shown in the dialog.
              */
             void onPrepareListView(ListView listView);
@@ -732,7 +875,7 @@
 
         private void createListView(final AlertController dialog) {
             final ListView listView = (ListView) mInflater.inflate(dialog.mListLayout, null);
-            ListAdapter adapter;
+            final ListAdapter adapter;
 
             if (mIsMultiChoice) {
                 if (mCursor == null) {
@@ -763,8 +906,8 @@
 
                         @Override
                         public void bindView(View view, Context context, Cursor cursor) {
-                            CheckedTextView text = (CheckedTextView) view
-                                    .findViewById(android.R.id.text1);
+                            CheckedTextView text = (CheckedTextView) view.findViewById(
+                                    android.R.id.text1);
                             text.setText(cursor.getString(mLabelIndex));
                             listView.setItemChecked(cursor.getPosition(),
                                     cursor.getInt(mIsCheckedIndex) == 1);
@@ -779,14 +922,20 @@
                     };
                 }
             } else {
-                int layout = mIsSingleChoice
-                        ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;
-                if (mCursor == null) {
-                    adapter = (mAdapter != null) ? mAdapter
-                            : new CheckedItemAdapter(mContext, layout, android.R.id.text1, mItems);
+                final int layout;
+                if (mIsSingleChoice) {
+                    layout = dialog.mSingleChoiceItemLayout;
                 } else {
-                    adapter = new SimpleCursorAdapter(mContext, layout,
-                            mCursor, new String[]{mLabelColumn}, new int[]{android.R.id.text1});
+                    layout = dialog.mListItemLayout;
+                }
+
+                if (mCursor != null) {
+                    adapter = new SimpleCursorAdapter(mContext, layout, mCursor,
+                            new String[] { mLabelColumn }, new int[] { android.R.id.text1 });
+                } else if (mAdapter != null) {
+                    adapter = mAdapter;
+                } else {
+                    adapter = new CheckedItemAdapter(mContext, layout, android.R.id.text1, mItems);
                 }
             }
 
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
index b22e209..ef38511 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
@@ -175,7 +175,16 @@
     public abstract MenuInflater getMenuInflater();
 
     /**
-     * Should be called from {@link Activity#onCreate Activity.onCreate()}
+     * Should be called from {@link Activity#onCreate Activity.onCreate()}.
+     *
+     * <p>This should be called before {@code super.onCreate()} as so:</p>
+     * <pre class="prettyprint">
+     * protected void onCreate(Bundle savedInstanceState) {
+     *     getDelegate().onCreate(savedInstanceState);
+     *     super.onCreate(savedInstanceState);
+     *     // ...
+     * }
+     * </pre>
      */
     public abstract void onCreate(Bundle savedInstanceState);
 
@@ -280,8 +289,8 @@
      * <pre class="prettyprint">
      * protected void onCreate(Bundle savedInstanceState) {
      *     getDelegate().installViewFactory();
-     *     super.onCreate(savedInstanceState);
      *     getDelegate().onCreate(savedInstanceState);
+     *     super.onCreate(savedInstanceState);
      *
      *     // ...
      * }
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
index b8182e6..394cf60 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
@@ -18,15 +18,13 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.WindowCallbackWrapper;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.widget.TintTypedArray;
 import android.support.v7.view.ActionMode;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.WindowCallbackWrapper;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.widget.TintTypedArray;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -54,6 +52,8 @@
     boolean mIsFloating;
     // true if this activity has no title
     boolean mWindowNoTitle;
+    // true if the theme has been read
+    boolean mThemeRead;
 
     private CharSequence mTitle;
 
@@ -276,8 +276,9 @@
 
         @Override
         public boolean onMenuOpened(int featureId, Menu menu) {
-            return super.onMenuOpened(featureId, menu)
-                    || AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu);
+            super.onMenuOpened(featureId, menu);
+            AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu);
+            return true;
         }
 
         @Override
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
index f134c48..35e7ca3 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
@@ -17,7 +17,7 @@
 package android.support.v7.app;
 
 import android.content.Context;
-import android.support.v7.internal.view.SupportActionModeWrapper;
+import android.support.v7.view.SupportActionModeWrapper;
 import android.view.ActionMode;
 import android.view.Window;
 
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
index 54ec0ad..e147b7d 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
@@ -31,6 +31,8 @@
 import android.os.Parcelable;
 import android.support.annotation.NonNull;
 import android.support.v4.app.NavUtils;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
 import android.support.v4.view.LayoutInflaterCompat;
 import android.support.v4.view.LayoutInflaterFactory;
 import android.support.v4.view.OnApplyWindowInsetsListener;
@@ -42,24 +44,21 @@
 import android.support.v4.view.WindowInsetsCompat;
 import android.support.v4.widget.PopupWindowCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.app.AppCompatViewInflater;
-import android.support.v7.internal.app.ToolbarActionBar;
-import android.support.v7.internal.app.WindowDecorActionBar;
-import android.support.v7.internal.view.ContextThemeWrapper;
-import android.support.v7.internal.view.StandaloneActionMode;
-import android.support.v7.internal.view.menu.ListMenuPresenter;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.widget.ActionBarContextView;
-import android.support.v7.internal.widget.ContentFrameLayout;
-import android.support.v7.internal.widget.DecorContentParent;
-import android.support.v7.internal.widget.FitWindowsViewGroup;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.ViewStubCompat;
-import android.support.v7.internal.widget.ViewUtils;
 import android.support.v7.view.ActionMode;
+import android.support.v7.view.ContextThemeWrapper;
+import android.support.v7.view.StandaloneActionMode;
+import android.support.v7.view.menu.ListMenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.widget.ActionBarContextView;
+import android.support.v7.widget.AppCompatDrawableManager;
+import android.support.v7.widget.ContentFrameLayout;
+import android.support.v7.widget.DecorContentParent;
+import android.support.v7.widget.FitWindowsViewGroup;
 import android.support.v7.widget.Toolbar;
+import android.support.v7.widget.ViewStubCompat;
+import android.support.v7.widget.ViewUtils;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 import android.util.AttributeSet;
@@ -116,6 +115,8 @@
     private PanelFeatureState[] mPanels;
     private PanelFeatureState mPreparedPanel;
 
+    private boolean mLongPressBackDown;
+
     private boolean mInvalidatePanelMenuPosted;
     private int mInvalidatePanelMenuFeatures;
     private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
@@ -461,6 +462,16 @@
             ((FrameLayout) decorContent).setForeground(null);
         }
 
+        abcContent.setAttachListener(new ContentFrameLayout.OnAttachListener() {
+            @Override
+            public void onAttachedFromWindow() {}
+
+            @Override
+            public void onDetachedFromWindow() {
+                dismissPopups();
+            }
+        });
+
         return subDecor;
     }
 
@@ -865,9 +876,17 @@
                 onKeyUpPanel(Window.FEATURE_OPTIONS_PANEL, event);
                 return true;
             case KeyEvent.KEYCODE_BACK:
+                final boolean wasLongPressBackDown = mLongPressBackDown;
+                mLongPressBackDown = false;
+
                 PanelFeatureState st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
                 if (st != null && st.isOpen) {
-                    closePanel(st, true);
+                    if (!wasLongPressBackDown) {
+                        // Certain devices allow opening the options menu via a long press of the
+                        // back button. We should only close the open options menu if it wasn't
+                        // opened via a long press gesture.
+                        closePanel(st, true);
+                    }
                     return true;
                 }
                 if (onBackPressed()) {
@@ -882,7 +901,14 @@
         switch (keyCode) {
             case KeyEvent.KEYCODE_MENU:
                 onKeyDownPanel(Window.FEATURE_OPTIONS_PANEL, event);
-                // Break, and let this fall through to the original callback
+                // We need to return true here and not let it bubble up to the Window.
+                // For empty menus, PhoneWindow's KEYCODE_BACK handling will steals all events,
+                // not allowing the Activity to call onBackPressed().
+                return true;
+            case KeyEvent.KEYCODE_BACK:
+                // Certain devices allow opening the options menu via a long press of the back
+                // button. We keep a record of whether the last event is from a long press.
+                mLongPressBackDown = (event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
                 break;
         }
 
@@ -1630,6 +1656,31 @@
         return mSubDecor;
     }
 
+    private void dismissPopups() {
+        if (mDecorContentParent != null) {
+            mDecorContentParent.dismissPopups();
+        }
+
+        if (mActionModePopup != null) {
+            mWindowDecor.removeCallbacks(mShowActionModePopup);
+            if (mActionModePopup.isShowing()) {
+                try {
+                    mActionModePopup.dismiss();
+                } catch (IllegalArgumentException e) {
+                    // Pre-v18, there are times when the Window will remove the popup before us.
+                    // In these cases we need to swallow the resulting exception.
+                }
+            }
+            mActionModePopup = null;
+        }
+        endOnGoingFadeAnimation();
+
+        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+        if (st != null && st.menu != null) {
+            st.menu.close();
+        }
+    }
+
     /**
      * Clears out internal reference when the action mode is destroyed.
      */
@@ -1924,32 +1975,35 @@
                 }
             }
 
-            private static SavedState readFromParcel(Parcel source) {
+            private static SavedState readFromParcel(Parcel source, ClassLoader loader) {
                 SavedState savedState = new SavedState();
                 savedState.featureId = source.readInt();
                 savedState.isOpen = source.readInt() == 1;
 
                 if (savedState.isOpen) {
-                    savedState.menuState = source.readBundle();
+                    savedState.menuState = source.readBundle(loader);
                 }
 
                 return savedState;
             }
 
             public static final Parcelable.Creator<SavedState> CREATOR
-                    = new Parcelable.Creator<SavedState>() {
-                public SavedState createFromParcel(Parcel in) {
-                    return readFromParcel(in);
-                }
+                    = ParcelableCompat.newCreator(
+                    new ParcelableCompatCreatorCallbacks<SavedState>() {
+                        @Override
+                        public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                            return readFromParcel(in, loader);
+                        }
 
-                public SavedState[] newArray(int size) {
-                    return new SavedState[size];
-                }
-            };
+                        @Override
+                        public SavedState[] newArray(int size) {
+                            return new SavedState[size];
+                        }
+                    });
         }
     }
 
-    private class ListMenuDecorView extends FrameLayout {
+    private class ListMenuDecorView extends ContentFrameLayout {
         public ListMenuDecorView(Context context) {
             super(context);
         }
@@ -1976,12 +2030,11 @@
 
         @Override
         public void setBackgroundResource(int resid) {
-            setBackgroundDrawable(TintManager.getDrawable(getContext(), resid));
+            setBackgroundDrawable(AppCompatDrawableManager.get().getDrawable(getContext(), resid));
         }
 
         private boolean isOutOfBounds(int x, int y) {
             return x < -5 || y < -5 || x > (getWidth() + 5) || y > (getHeight() + 5);
         }
     }
-
 }
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java b/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
new file mode 100644
index 0000000..a74623e
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
@@ -0,0 +1,312 @@
+/*
+ * 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 android.support.v7.app;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.TypedArray;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.appcompat.R;
+import android.support.v7.view.ContextThemeWrapper;
+import android.support.v7.widget.AppCompatAutoCompleteTextView;
+import android.support.v7.widget.AppCompatButton;
+import android.support.v7.widget.AppCompatCheckBox;
+import android.support.v7.widget.AppCompatCheckedTextView;
+import android.support.v7.widget.AppCompatEditText;
+import android.support.v7.widget.AppCompatImageButton;
+import android.support.v7.widget.AppCompatImageView;
+import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
+import android.support.v7.widget.AppCompatRadioButton;
+import android.support.v7.widget.AppCompatRatingBar;
+import android.support.v7.widget.AppCompatSeekBar;
+import android.support.v7.widget.AppCompatSpinner;
+import android.support.v7.widget.AppCompatTextView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.InflateException;
+import android.view.View;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * This class is responsible for manually inflating our tinted widgets which are used on devices
+ * running {@link android.os.Build.VERSION_CODES#KITKAT KITKAT} or below. As such, this class
+ * should only be used when running on those devices.
+ * <p>This class two main responsibilities: the first is to 'inject' our tinted views in place of
+ * the framework versions in layout inflation; the second is backport the {@code android:theme}
+ * functionality for any inflated widgets. This include theme inheritance from it's parent.
+ */
+class AppCompatViewInflater {
+
+    private static final Class<?>[] sConstructorSignature = new Class[]{
+            Context.class, AttributeSet.class};
+    private static final int[] sOnClickAttrs = new int[]{android.R.attr.onClick};
+
+    private static final String LOG_TAG = "AppCompatViewInflater";
+
+    private static final Map<String, Constructor<? extends View>> sConstructorMap
+            = new ArrayMap<>();
+
+    private final Object[] mConstructorArgs = new Object[2];
+
+    public final View createView(View parent, final String name, @NonNull Context context,
+            @NonNull AttributeSet attrs, boolean inheritContext,
+            boolean readAndroidTheme, boolean readAppTheme) {
+        final Context originalContext = context;
+
+        // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
+        // by using the parent's context
+        if (inheritContext && parent != null) {
+            context = parent.getContext();
+        }
+        if (readAndroidTheme || readAppTheme) {
+            // We then apply the theme on the context, if specified
+            context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
+        }
+
+        View view = null;
+
+        // We need to 'inject' our tint aware Views in place of the standard framework versions
+        switch (name) {
+            case "TextView":
+                view = new AppCompatTextView(context, attrs);
+                break;
+            case "ImageView":
+                view = new AppCompatImageView(context, attrs);
+                break;
+            case "Button":
+                view = new AppCompatButton(context, attrs);
+                break;
+            case "EditText":
+                view = new AppCompatEditText(context, attrs);
+                break;
+            case "Spinner":
+                view = new AppCompatSpinner(context, attrs);
+                break;
+            case "ImageButton":
+                view = new AppCompatImageButton(context, attrs);
+                break;
+            case "CheckBox":
+                view = new AppCompatCheckBox(context, attrs);
+                break;
+            case "RadioButton":
+                view = new AppCompatRadioButton(context, attrs);
+                break;
+            case "CheckedTextView":
+                view = new AppCompatCheckedTextView(context, attrs);
+                break;
+            case "AutoCompleteTextView":
+                view = new AppCompatAutoCompleteTextView(context, attrs);
+                break;
+            case "MultiAutoCompleteTextView":
+                view = new AppCompatMultiAutoCompleteTextView(context, attrs);
+                break;
+            case "RatingBar":
+                view = new AppCompatRatingBar(context, attrs);
+                break;
+            case "SeekBar":
+                view = new AppCompatSeekBar(context, attrs);
+                break;
+        }
+
+        if (view == null && originalContext != context) {
+            // If the original context does not equal our themed context, then we need to manually
+            // inflate it using the name so that android:theme takes effect.
+            view = createViewFromTag(context, name, attrs);
+        }
+
+        if (view != null) {
+            // If we have created a view, check it's android:onClick
+            checkOnClickListener(view, attrs);
+        }
+
+        return view;
+    }
+
+    private View createViewFromTag(Context context, String name, AttributeSet attrs) {
+        if (name.equals("view")) {
+            name = attrs.getAttributeValue(null, "class");
+        }
+
+        try {
+            mConstructorArgs[0] = context;
+            mConstructorArgs[1] = attrs;
+
+            if (-1 == name.indexOf('.')) {
+                // try the android.widget prefix first...
+                return createView(context, name, "android.widget.");
+            } else {
+                return createView(context, name, null);
+            }
+        } catch (Exception e) {
+            // We do not want to catch these, lets return null and let the actual LayoutInflater
+            // try
+            return null;
+        } finally {
+            // Don't retain references on context.
+            mConstructorArgs[0] = null;
+            mConstructorArgs[1] = null;
+        }
+    }
+
+    /**
+     * android:onClick doesn't handle views with a ContextWrapper context. This method
+     * backports new framework functionality to traverse the Context wrappers to find a
+     * suitable target.
+     */
+    private void checkOnClickListener(View view, AttributeSet attrs) {
+        final Context context = view.getContext();
+
+        if (!ViewCompat.hasOnClickListeners(view) || !(context instanceof ContextWrapper)) {
+            // Skip our compat functionality if: the view doesn't have an onClickListener,
+            // or the Context isn't a ContextWrapper
+            return;
+        }
+
+        final TypedArray a = context.obtainStyledAttributes(attrs, sOnClickAttrs);
+        final String handlerName = a.getString(0);
+        if (handlerName != null) {
+            view.setOnClickListener(new DeclaredOnClickListener(view, handlerName));
+        }
+        a.recycle();
+    }
+
+    private View createView(Context context, String name, String prefix)
+            throws ClassNotFoundException, InflateException {
+        Constructor<? extends View> constructor = sConstructorMap.get(name);
+
+        try {
+            if (constructor == null) {
+                // Class not found in the cache, see if it's real, and try to add it
+                Class<? extends View> clazz = context.getClassLoader().loadClass(
+                        prefix != null ? (prefix + name) : name).asSubclass(View.class);
+
+                constructor = clazz.getConstructor(sConstructorSignature);
+                sConstructorMap.put(name, constructor);
+            }
+            constructor.setAccessible(true);
+            return constructor.newInstance(mConstructorArgs);
+        } catch (Exception e) {
+            // We do not want to catch these, lets return null and let the actual LayoutInflater
+            // try
+            return null;
+        }
+    }
+
+    /**
+     * Allows us to emulate the {@code android:theme} attribute for devices before L.
+     */
+    private static Context themifyContext(Context context, AttributeSet attrs,
+            boolean useAndroidTheme, boolean useAppTheme) {
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0);
+        int themeId = 0;
+        if (useAndroidTheme) {
+            // First try reading android:theme if enabled
+            themeId = a.getResourceId(R.styleable.View_android_theme, 0);
+        }
+        if (useAppTheme && themeId == 0) {
+            // ...if that didn't work, try reading app:theme (for legacy reasons) if enabled
+            themeId = a.getResourceId(R.styleable.View_theme, 0);
+
+            if (themeId != 0) {
+                Log.i(LOG_TAG, "app:theme is now deprecated. "
+                        + "Please move to using android:theme instead.");
+            }
+        }
+        a.recycle();
+
+        if (themeId != 0 && (!(context instanceof ContextThemeWrapper)
+                || ((ContextThemeWrapper) context).getThemeResId() != themeId)) {
+            // If the context isn't a ContextThemeWrapper, or it is but does not have
+            // the same theme as we need, wrap it in a new wrapper
+            context = new ContextThemeWrapper(context, themeId);
+        }
+        return context;
+    }
+
+    /**
+     * An implementation of OnClickListener that attempts to lazily load a
+     * named click handling method from a parent or ancestor context.
+     */
+    private static class DeclaredOnClickListener implements View.OnClickListener {
+        private final View mHostView;
+        private final String mMethodName;
+
+        private Method mResolvedMethod;
+        private Context mResolvedContext;
+
+        public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
+            mHostView = hostView;
+            mMethodName = methodName;
+        }
+
+        @Override
+        public void onClick(@NonNull View v) {
+            if (mResolvedMethod == null) {
+                resolveMethod(mHostView.getContext(), mMethodName);
+            }
+
+            try {
+                mResolvedMethod.invoke(mResolvedContext, v);
+            } catch (IllegalAccessException e) {
+                throw new IllegalStateException(
+                        "Could not execute non-public method for android:onClick", e);
+            } catch (InvocationTargetException e) {
+                throw new IllegalStateException(
+                        "Could not execute method for android:onClick", e);
+            }
+        }
+
+        @NonNull
+        private void resolveMethod(@Nullable Context context, @NonNull String name) {
+            while (context != null) {
+                try {
+                    if (!context.isRestricted()) {
+                        final Method method = context.getClass().getMethod(mMethodName, View.class);
+                        if (method != null) {
+                            mResolvedMethod = method;
+                            mResolvedContext = context;
+                            return;
+                        }
+                    }
+                } catch (NoSuchMethodException e) {
+                    // Failed to find method, keep searching up the hierarchy.
+                }
+
+                if (context instanceof ContextWrapper) {
+                    context = ((ContextWrapper) context).getBaseContext();
+                } else {
+                    // Can't search up the hierarchy, null out and fail.
+                    context = null;
+                }
+            }
+
+            final int id = mHostView.getId();
+            final String idText = id == View.NO_ID ? "" : " with id '"
+                    + mHostView.getContext().getResources().getResourceEntryName(id) + "'";
+            throw new IllegalStateException("Could not find method " + mMethodName
+                    + "(View) in a parent or ancestor Context for android:onClick "
+                    + "attribute defined on view " + mHostView.getClass() + idText);
+        }
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java b/v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java
similarity index 93%
rename from v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java
rename to v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java
index 41e684a..39b5bfe 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java
+++ b/v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java
@@ -15,17 +15,14 @@
  */
 
 
-package android.support.v7.internal.app;
+package android.support.v7.app;
 
-import android.support.v7.app.ActionBar;
 import android.view.View;
 import android.widget.AdapterView;
 
 /**
  * Wrapper to adapt the ActionBar.OnNavigationListener in an AdapterView.OnItemSelectedListener
  * for use in Spinner widgets. Used by action bar implementations.
- *
- * @hide
  */
 class NavItemSelectedListener implements AdapterView.OnItemSelectedListener {
     private final ActionBar.OnNavigationListener mListener;
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
index 689d47f..514ebef 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
@@ -22,8 +22,6 @@
 import android.os.Build;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
 import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v7.internal.app.NotificationCompatImpl21;
-import android.support.v7.internal.app.NotificationCompatImplBase;
 
 /**
  * An extension of {@link android.support.v4.app.NotificationCompat} which supports
diff --git a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImpl21.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
similarity index 92%
rename from v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImpl21.java
rename to v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
index a68ad81d..cfa8839 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImpl21.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.app;
+package android.support.v7.app;
 
 import android.app.Notification;
 import android.media.session.MediaSession;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
 
-/**
- * @hide
- */
-public class NotificationCompatImpl21 {
+class NotificationCompatImpl21 {
 
     public static void addMediaStyle(NotificationBuilderWithBuilderAccessor b,
             int[] actionsToShowInCompact,
diff --git a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImplBase.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImplBase.java
rename to v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
index c52290dc..2bd772c 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.support.v7.internal.app;
+package android.support.v7.app;
 
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -23,9 +23,9 @@
 import android.graphics.Bitmap;
 import android.os.Build;
 import android.os.SystemClock;
-import android.support.v7.appcompat.R;
 import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
 import android.support.v4.app.NotificationCompatBase;
+import android.support.v7.appcompat.R;
 import android.util.TypedValue;
 import android.view.View;
 import android.widget.RemoteViews;
@@ -36,9 +36,8 @@
 /**
  * Helper class to generate MediaStyle notifications for pre-Lollipop platforms. Overrides
  * contentView and bigContentView of the notification.
- * @hide
  */
-public class NotificationCompatImplBase {
+class NotificationCompatImplBase {
 
     static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
     static final int MAX_MEDIA_BUTTONS = 5;
@@ -173,6 +172,7 @@
         // 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) {
+            contentView.setViewVisibility(R.id.icon, View.VISIBLE);
             contentView.setImageViewBitmap(R.id.icon, largeIcon);
         } else {
             contentView.setViewVisibility(R.id.icon, View.GONE);
diff --git a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
rename to v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
index cb8de47..aa1a0ae 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.app;
+package android.support.v7.app;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -22,16 +22,14 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.Nullable;
 import android.support.v4.view.ViewCompat;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatDelegate;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.WindowCallbackWrapper;
-import android.support.v7.internal.view.menu.ListMenuPresenter;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.widget.DecorToolbar;
-import android.support.v7.internal.widget.ToolbarWidgetWrapper;
+import android.support.v7.view.WindowCallbackWrapper;
+import android.support.v7.view.menu.ListMenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.widget.DecorToolbar;
 import android.support.v7.widget.Toolbar;
+import android.support.v7.widget.ToolbarWidgetWrapper;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.KeyCharacterMap;
@@ -45,10 +43,7 @@
 
 import java.util.ArrayList;
 
-/**
- * @hide
- */
-public class ToolbarActionBar extends ActionBar {
+class ToolbarActionBar extends ActionBar {
     private DecorToolbar mDecorToolbar;
     private boolean mToolbarMenuPrepared;
     private Window.Callback mWindowCallback;
diff --git a/v7/appcompat/src/android/support/v7/app/TwilightManager.java b/v7/appcompat/src/android/support/v7/app/TwilightManager.java
index b17d578..e1731de 100644
--- a/v7/appcompat/src/android/support/v7/app/TwilightManager.java
+++ b/v7/appcompat/src/android/support/v7/app/TwilightManager.java
@@ -79,31 +79,27 @@
     }
 
     private Location getLastKnownLocation() {
-        Location coarseLocation = null;
-        Location fineLocation = null;
+        Location coarseLoc = null;
+        Location fineLoc = null;
 
         int permission = PermissionChecker.checkSelfPermission(mContext,
-                Manifest.permission.ACCESS_FINE_LOCATION);
+                Manifest.permission.ACCESS_COARSE_LOCATION);
         if (permission == PermissionChecker.PERMISSION_GRANTED) {
-            coarseLocation = getLastKnownLocationForProvider(LocationManager.NETWORK_PROVIDER);
+            coarseLoc = getLastKnownLocationForProvider(LocationManager.NETWORK_PROVIDER);
         }
 
         permission = PermissionChecker.checkSelfPermission(mContext,
-                Manifest.permission.ACCESS_COARSE_LOCATION);
+                Manifest.permission.ACCESS_FINE_LOCATION);
         if (permission == PermissionChecker.PERMISSION_GRANTED) {
-            fineLocation = getLastKnownLocationForProvider(LocationManager.GPS_PROVIDER);
+            fineLoc = getLastKnownLocationForProvider(LocationManager.GPS_PROVIDER);
         }
 
-        if (coarseLocation != null && fineLocation != null) {
+        if (fineLoc != null && coarseLoc != null) {
             // If we have both a fine and coarse location, use the latest
-            if (fineLocation.getTime() > coarseLocation.getTime()) {
-                return fineLocation;
-            } else {
-                return coarseLocation;
-            }
+            return fineLoc.getTime() > coarseLoc.getTime() ? fineLoc : coarseLoc;
         } else {
             // Else, return the non-null one (if there is one)
-            return fineLocation != null ? fineLocation : coarseLocation;
+            return fineLoc != null ? fineLoc : coarseLoc;
         }
     }
 
diff --git a/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java
rename to v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
index e76f658..2ec054b 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.app;
+package android.support.v7.app;
 
 import android.app.Activity;
 import android.app.Dialog;
@@ -31,21 +31,20 @@
 import android.support.v4.view.ViewPropertyAnimatorListener;
 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
 import android.support.v4.view.ViewPropertyAnimatorUpdateListener;
-import android.support.v7.app.ActionBar;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ActionBarPolicy;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.ActionBarContainer;
-import android.support.v7.internal.widget.ActionBarContextView;
-import android.support.v7.internal.widget.ActionBarOverlayLayout;
-import android.support.v7.internal.widget.DecorToolbar;
-import android.support.v7.internal.widget.ScrollingTabContainerView;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.view.ActionBarPolicy;
 import android.support.v7.view.ActionMode;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.ViewPropertyAnimatorCompatSet;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.SubMenuBuilder;
+import android.support.v7.widget.ActionBarContainer;
+import android.support.v7.widget.ActionBarContextView;
+import android.support.v7.widget.ActionBarOverlayLayout;
+import android.support.v7.widget.AppCompatDrawableManager;
+import android.support.v7.widget.DecorToolbar;
+import android.support.v7.widget.ScrollingTabContainerView;
 import android.support.v7.widget.Toolbar;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
@@ -58,7 +57,6 @@
 import android.view.Window;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.SpinnerAdapter;
@@ -132,8 +130,6 @@
     private boolean mShowHideAnimationEnabled;
     boolean mHideOnContentScroll;
 
-    private TintManager mTintManager;
-
     final ViewPropertyAnimatorListener mHideListener = new ViewPropertyAnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(View view) {
@@ -846,7 +842,11 @@
 
         ViewPropertyAnimatorCompat fadeIn, fadeOut;
         if (toActionMode) {
-            fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE,
+            // We use INVISIBLE for the Toolbar to make sure that the container has a non-zero
+            // height throughout. The context view is GONE initially, so will not have been laid
+            // out when the animation starts. This can lead to the container collapsing to 0px
+            // height for a short period.
+            fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.INVISIBLE,
                     FADE_OUT_DURATION_MS);
             fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE,
                     FADE_IN_DURATION_MS);
@@ -1180,7 +1180,7 @@
 
         @Override
         public Tab setIcon(int resId) {
-            return setIcon(getTintManager().getDrawable(resId));
+            return setIcon(AppCompatDrawableManager.get().getDrawable(mContext, resId));
         }
 
         @Override
@@ -1336,12 +1336,4 @@
             setDisplayHomeAsUpEnabled(enable);
         }
     }
-
-    TintManager getTintManager() {
-        if (mTintManager == null) {
-            mTintManager = TintManager.get(mContext);
-        }
-        return mTintManager;
-    }
-
 }
diff --git a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
index 82e8f18..2c658b1 100644
--- a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
+++ b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
@@ -447,6 +447,13 @@
     }
 
     /**
+     * Returns the paint instance used for all drawing.
+     */
+    public final Paint getPaint() {
+        return mPaint;
+    }
+
+    /**
      * Linear interpolate between a and b with parameter t.
      */
     private static float lerp(float a, float b, float t) {
diff --git a/v7/appcompat/src/android/support/v7/internal/VersionUtils.java b/v7/appcompat/src/android/support/v7/internal/VersionUtils.java
deleted file mode 100644
index babd65c..0000000
--- a/v7/appcompat/src/android/support/v7/internal/VersionUtils.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package android.support.v7.internal;
-
-import android.os.Build;
-
-/**
- * @hide
- */
-public class VersionUtils {
-
-    private VersionUtils() {}
-
-    public static boolean isAtLeastL() {
-        return Build.VERSION.SDK_INT >= 21;
-    }
-
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java b/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java
deleted file mode 100644
index 621fc51..0000000
--- a/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java
+++ /dev/null
@@ -1,193 +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 android.support.v7.internal.app;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.annotation.NonNull;
-import android.support.v4.util.ArrayMap;
-import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ContextThemeWrapper;
-import android.support.v7.widget.AppCompatAutoCompleteTextView;
-import android.support.v7.widget.AppCompatButton;
-import android.support.v7.widget.AppCompatCheckBox;
-import android.support.v7.widget.AppCompatCheckedTextView;
-import android.support.v7.widget.AppCompatEditText;
-import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
-import android.support.v7.widget.AppCompatRadioButton;
-import android.support.v7.widget.AppCompatRatingBar;
-import android.support.v7.widget.AppCompatSpinner;
-import android.support.v7.internal.widget.ViewUtils;
-import android.support.v7.widget.AppCompatTextView;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.InflateException;
-import android.view.View;
-
-import java.lang.reflect.Constructor;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * This class is responsible for manually inflating our tinted widgets which are used on devices
- * running {@link android.os.Build.VERSION_CODES#KITKAT KITKAT} or below. As such, this class
- * should only be used when running on those devices.
- * <p>This class two main responsibilities: the first is to 'inject' our tinted views in place of
- * the framework versions in layout inflation; the second is backport the {@code android:theme}
- * functionality for any inflated widgets. This include theme inheritance from it's parent.
- *
- * @hide
- */
-public class AppCompatViewInflater {
-
-    static final Class<?>[] sConstructorSignature = new Class[]{
-            Context.class, AttributeSet.class};
-
-    private static final String LOG_TAG = "AppCompatViewInflater";
-
-    private static final Map<String, Constructor<? extends View>> sConstructorMap
-            = new ArrayMap<>();
-
-    private final Object[] mConstructorArgs = new Object[2];
-
-    public final View createView(View parent, final String name, @NonNull Context context,
-            @NonNull AttributeSet attrs, boolean inheritContext,
-            boolean readAndroidTheme, boolean readAppTheme) {
-        final Context originalContext = context;
-
-        // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
-        // by using the parent's context
-        if (inheritContext && parent != null) {
-            context = parent.getContext();
-        }
-        if (readAndroidTheme || readAppTheme) {
-            // We then apply the theme on the context, if specified
-            context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
-        }
-
-        // We need to 'inject' our tint aware Views in place of the standard framework versions
-        switch (name) {
-            case "EditText":
-                return new AppCompatEditText(context, attrs);
-            case "Spinner":
-                return new AppCompatSpinner(context, attrs);
-            case "CheckBox":
-                return new AppCompatCheckBox(context, attrs);
-            case "RadioButton":
-                return new AppCompatRadioButton(context, attrs);
-            case "CheckedTextView":
-                return new AppCompatCheckedTextView(context, attrs);
-            case "AutoCompleteTextView":
-                return new AppCompatAutoCompleteTextView(context, attrs);
-            case "MultiAutoCompleteTextView":
-                return new AppCompatMultiAutoCompleteTextView(context, attrs);
-            case "RatingBar":
-                return new AppCompatRatingBar(context, attrs);
-            case "Button":
-                return new AppCompatButton(context, attrs);
-            case "TextView":
-                return new AppCompatTextView(context, attrs);
-        }
-
-        if (originalContext != context) {
-            // If the original context does not equal our themed context, then we need to manually
-            // inflate it using the name so that android:theme takes effect.
-            return createViewFromTag(context, name, attrs);
-        }
-
-        return null;
-    }
-
-    private View createViewFromTag(Context context, String name, AttributeSet attrs) {
-        if (name.equals("view")) {
-            name = attrs.getAttributeValue(null, "class");
-        }
-
-        try {
-            mConstructorArgs[0] = context;
-            mConstructorArgs[1] = attrs;
-
-            if (-1 == name.indexOf('.')) {
-                // try the android.widget prefix first...
-                return createView(context, name, "android.widget.");
-            } else {
-                return createView(context, name, null);
-            }
-        } catch (Exception e) {
-            // We do not want to catch these, lets return null and let the actual LayoutInflater
-            // try
-            return null;
-        } finally {
-            // Don't retain references on context.
-            mConstructorArgs[0] = null;
-            mConstructorArgs[1] = null;
-        }
-    }
-
-    private View createView(Context context, String name, String prefix)
-            throws ClassNotFoundException, InflateException {
-        Constructor<? extends View> constructor = sConstructorMap.get(name);
-
-        try {
-            if (constructor == null) {
-                // Class not found in the cache, see if it's real, and try to add it
-                Class<? extends View> clazz = context.getClassLoader().loadClass(
-                        prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
-                constructor = clazz.getConstructor(sConstructorSignature);
-                sConstructorMap.put(name, constructor);
-            }
-            constructor.setAccessible(true);
-            return constructor.newInstance(mConstructorArgs);
-        } catch (Exception e) {
-            // We do not want to catch these, lets return null and let the actual LayoutInflater
-            // try
-            return null;
-        }
-    }
-
-    /**
-     * Allows us to emulate the {@code android:theme} attribute for devices before L.
-     */
-    private static Context themifyContext(Context context, AttributeSet attrs,
-            boolean useAndroidTheme, boolean useAppTheme) {
-        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0);
-        int themeId = 0;
-        if (useAndroidTheme) {
-            // First try reading android:theme if enabled
-            themeId = a.getResourceId(R.styleable.View_android_theme, 0);
-        }
-        if (useAppTheme && themeId == 0) {
-            // ...if that didn't work, try reading app:theme (for legacy reasons) if enabled
-            themeId = a.getResourceId(R.styleable.View_theme, 0);
-
-            if (themeId != 0) {
-                Log.i(LOG_TAG, "app:theme is now deprecated. "
-                        + "Please move to using android:theme instead.");
-            }
-        }
-        a.recycle();
-
-        if (themeId != 0 && (!(context instanceof ContextThemeWrapper)
-                || ((ContextThemeWrapper) context).getThemeResId() != themeId)) {
-            // If the context isn't a ContextThemeWrapper, or it is but does not have
-            // the same theme as we need, wrap it in a new wrapper
-            context = new ContextThemeWrapper(context, themeId);
-        }
-        return context;
-    }
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawableV21.java b/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawableV21.java
deleted file mode 100644
index 19cd5a1..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawableV21.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package android.support.v7.internal.widget;
-
-import android.graphics.Outline;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-
-class ActionBarBackgroundDrawableV21 extends ActionBarBackgroundDrawable {
-
-    public ActionBarBackgroundDrawableV21(ActionBarContainer container) {
-        super(container);
-    }
-
-    @Override
-    public void getOutline(@NonNull Outline outline) {
-        if (mContainer.mIsSplit) {
-            if (mContainer.mSplitBackground != null) {
-                mContainer.mSplitBackground.getOutline(outline);
-            }
-        } else {
-            // ignore the stacked background for shadow casting
-            if (mContainer.mBackground != null) {
-                mContainer.mBackground.getOutline(outline);
-            }
-        }
-    }
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java b/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java
deleted file mode 100644
index 17dd557..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java
+++ /dev/null
@@ -1,70 +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 android.support.v7.internal.widget;
-
-import android.content.Context;
-import android.support.annotation.DrawableRes;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-/**
- * An tint aware {@link android.widget.ImageView}
- *
- * @hide
- */
-public class TintImageView extends ImageView {
-
-    private static final int[] TINT_ATTRS = {
-            android.R.attr.background,
-            android.R.attr.src
-    };
-
-    private final TintManager mTintManager;
-
-    public TintImageView(Context context) {
-        this(context, null);
-    }
-
-    public TintImageView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TintImageView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, TINT_ATTRS,
-                defStyleAttr, 0);
-        if (a.length() > 0) {
-            if (a.hasValue(0)) {
-                setBackgroundDrawable(a.getDrawable(0));
-            }
-            if (a.hasValue(1)) {
-                setImageDrawable(a.getDrawable(1));
-            }
-        }
-        a.recycle();
-
-        // Keep the TintManager in case we need it later
-        mTintManager = a.getTintManager();
-    }
-
-    @Override
-    public void setImageResource(@DrawableRes int resId) {
-        // Intercept this call and instead retrieve the Drawable via the tint manager
-        setImageDrawable(mTintManager.getDrawable(resId));
-    }
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/text/AllCapsTransformationMethod.java b/v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/text/AllCapsTransformationMethod.java
rename to v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java
index 76d1aed..7150262 100644
--- a/v7/appcompat/src/android/support/v7/internal/text/AllCapsTransformationMethod.java
+++ b/v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.text;
+package android.support.v7.text;
 
 import android.content.Context;
 import android.graphics.Rect;
diff --git a/v7/appcompat/src/android/support/v7/internal/transition/ActionBarTransition.java b/v7/appcompat/src/android/support/v7/transition/ActionBarTransition.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/transition/ActionBarTransition.java
rename to v7/appcompat/src/android/support/v7/transition/ActionBarTransition.java
index bc4ad04..6cffd53 100644
--- a/v7/appcompat/src/android/support/v7/internal/transition/ActionBarTransition.java
+++ b/v7/appcompat/src/android/support/v7/transition/ActionBarTransition.java
@@ -15,7 +15,7 @@
  */
 
 
-package android.support.v7.internal.transition;
+package android.support.v7.transition;
 
 import android.view.ViewGroup;
 
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ActionBarPolicy.java b/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/ActionBarPolicy.java
rename to v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
index dc5c4f0..0e50cc1 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ActionBarPolicy.java
+++ b/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view;
+package android.support.v7.view;
 
 import android.content.Context;
 import android.content.res.Resources;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java b/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java
rename to v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
index d8932ee..6b77fd6 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view;
+package android.support.v7.view;
 
 import android.content.Context;
 import android.content.ContextWrapper;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/StandaloneActionMode.java b/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
similarity index 92%
rename from v7/appcompat/src/android/support/v7/internal/view/StandaloneActionMode.java
rename to v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
index 887b43d..7f4c87e 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/StandaloneActionMode.java
+++ b/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
@@ -13,15 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.v7.internal.view;
+package android.support.v7.view;
 
 import android.content.Context;
 import android.support.v4.view.MenuItemCompat;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.ActionBarContextView;
-import android.support.v7.view.ActionMode;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.SubMenuBuilder;
+import android.support.v7.widget.ActionBarContextView;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/SupportActionModeWrapper.java b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/SupportActionModeWrapper.java
rename to v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
index 2c09e64..7eb6354 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/SupportActionModeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view;
+package android.support.v7.view;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -22,7 +22,7 @@
 import android.support.v4.internal.view.SupportMenu;
 import android.support.v4.internal.view.SupportMenuItem;
 import android.support.v4.util.SimpleArrayMap;
-import android.support.v7.internal.view.menu.MenuWrapperFactory;
+import android.support.v7.view.menu.MenuWrapperFactory;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuInflater;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
rename to v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
index 7bc3978..c8004ee 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view;
+package android.support.v7.view;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -28,8 +28,8 @@
 import android.support.v4.view.ActionProvider;
 import android.support.v4.view.MenuItemCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuItemWrapperICS;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuItemWrapperICS;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java b/v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java
rename to v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
index ec1d567..8727c9d 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java
+++ b/v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view;
+package android.support.v7.view;
 
 import android.support.v4.view.ViewPropertyAnimatorCompat;
 import android.support.v4.view.ViewPropertyAnimatorListener;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java b/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java
rename to v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
index 900d304..45278bc 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view;
+package android.support.v7.view;
 
 import android.view.ActionMode;
 import android.view.KeyEvent;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItem.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItem.java
rename to v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
index b466a0b..5e6ea31 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItem.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ActionProvider;
 import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v4.view.ActionProvider;
 import android.support.v4.view.MenuItemCompat;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.MenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItemView.java
rename to v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
index b7f5ff7..0b80cf2 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.content.res.Configuration;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuPresenter.java
rename to v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
index 34cc821..868ff41 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.support.v4.view.ViewCompat;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuWrapper.java b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuWrapper.java
rename to v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java
index b8f7793..1a31ec6 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.support.v4.internal.view.SupportMenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseWrapper.java b/v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java
similarity index 94%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/BaseWrapper.java
rename to v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java
index 116bc23..35422ca 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 class BaseWrapper<T> {
 
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ExpandedMenuView.java b/v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java
similarity index 90%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ExpandedMenuView.java
rename to v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java
index fa12f67..202c46a 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ExpandedMenuView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuBuilder.ItemInvoker;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.widget.TintTypedArray;
+import android.support.v7.view.menu.MenuBuilder.ItemInvoker;
+import android.support.v7.widget.TintTypedArray;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.AdapterView;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuItemView.java
rename to v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
index ebb9529..388e78f 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuPresenter.java
rename to v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
index ac98840..a0b7359 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
@@ -14,10 +14,9 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
-import android.database.DataSetObserver;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.support.v7.appcompat.R;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuBuilder.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
index 16624c7..b976655 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -27,11 +27,11 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.appcompat.R;
-import android.support.v4.view.ActionProvider;
 import android.support.v4.internal.view.SupportMenu;
 import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v4.view.ActionProvider;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.appcompat.R;
 import android.util.SparseArray;
 import android.view.ContextMenu;
 import android.view.KeyCharacterMap;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuDialogHelper.java b/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuDialogHelper.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
index dc4e9f52..6e4036f 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuDialogHelper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.app.Dialog;
 import android.content.DialogInterface;
@@ -28,10 +28,8 @@
 
 /**
  * Helper for menus that appear as Dialogs (context and submenus).
- *
- * @hide
  */
-public class MenuDialogHelper implements DialogInterface.OnKeyListener,
+class MenuDialogHelper implements DialogInterface.OnKeyListener,
         DialogInterface.OnClickListener,
         DialogInterface.OnDismissListener,
         MenuPresenter.Callback {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
index ffddb31..7709a36 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
@@ -14,18 +14,17 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ActionProvider;
 import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v4.view.ActionProvider;
 import android.support.v4.view.MenuItemCompat;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.widget.AppCompatDrawableManager;
 import android.util.Log;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.LayoutInflater;
@@ -419,7 +418,8 @@
         }
 
         if (mIconResId != NO_ICON) {
-            Drawable icon = TintManager.getDrawable(mMenu.getContext(), mIconResId);
+            Drawable icon = AppCompatDrawableManager.get()
+                    .getDrawable(mMenu.getContext(), mIconResId);
             mIconResId = NO_ICON;
             mIconDrawable = icon;
             return icon;
@@ -538,7 +538,7 @@
 
     @Override
     public String toString() {
-        return mTitle.toString();
+        return mTitle != null ? mTitle.toString() : null;
     }
 
     void setMenuInfo(ContextMenuInfo menuInfo) {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
index 3e6a99a..a717628 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.annotation.TargetApi;
 import android.content.Context;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperJB.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperJB.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
index 4dbb0e0..9a02b4f 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperJB.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.annotation.TargetApi;
 import android.content.Context;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java b/v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java
index bdcc79a..c0e0fb5 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.content.res.Resources;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuPresenter.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java
index 4e92426..cf414fc 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.os.Parcelable;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuView.java b/v7/appcompat/src/android/support/v7/view/menu/MenuView.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuView.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuView.java
index 7a3aabc..a4d9310 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.graphics.drawable.Drawable;
 
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperFactory.java b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperFactory.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java
index 74358747..0130822 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperFactory.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.os.Build;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperICS.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
index 79833f5..e733427 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.support.v4.internal.view.SupportMenu;
-import android.support.v4.internal.view.SupportMenuItem;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuBuilder.java
rename to v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
index 90bf77f..a213b77 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuWrapperICS.java
rename to v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
index a4306e9..9c1d5e5 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java b/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java
rename to v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
index 0824828..2121b74 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -25,8 +25,6 @@
 import android.support.v4.view.ViewPropertyAnimatorCompat;
 import android.support.v4.view.ViewPropertyAnimatorListener;
 import android.support.v7.appcompat.R;
-import android.support.v7.widget.ActionMenuPresenter;
-import android.support.v7.widget.ActionMenuView;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawable.java b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
similarity index 61%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawable.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
index 6248f79..b2fa191 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawable.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
@@ -1,4 +1,20 @@
-package android.support.v7.internal.widget;
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
 
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
new file mode 100644
index 0000000..0b05fe7
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.graphics.Outline;
+import android.support.annotation.NonNull;
+
+class ActionBarBackgroundDrawableV21 extends ActionBarBackgroundDrawable {
+
+    public ActionBarBackgroundDrawableV21(ActionBarContainer container) {
+        super(container);
+    }
+
+    @Override
+    public void getOutline(@NonNull Outline outline) {
+        if (mContainer.mIsSplit) {
+            if (mContainer.mSplitBackground != null) {
+                mContainer.mSplitBackground.getOutline(outline);
+            }
+        } else {
+            // ignore the stacked background for shadow casting
+            if (mContainer.mBackground != null) {
+                mContainer.mBackground.getOutline(outline);
+            }
+        }
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContainer.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarContainer.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
index 239fe4c..c8c69ea 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContainer.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.VersionUtils;
 import android.support.v7.view.ActionMode;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -55,7 +54,7 @@
         super(context, attrs);
 
         // Set a transparent background so that we project appropriately.
-        final Drawable bg = VersionUtils.isAtLeastL()
+        final Drawable bg = Build.VERSION.SDK_INT >= 21
                 ? new ActionBarBackgroundDrawableV21(this)
                 : new ActionBarBackgroundDrawable(this);
         setBackgroundDrawable(bg);
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
index 7c5d221..4f45c2a 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.menu.MenuBuilder;
 import android.support.v7.view.ActionMode;
-import android.support.v7.widget.ActionMenuPresenter;
-import android.support.v7.widget.ActionMenuView;
+import android.support.v7.view.menu.MenuBuilder;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java b/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
index d647d7f..9623383 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -33,9 +33,7 @@
 import android.support.v4.widget.ScrollerCompat;
 import android.support.v7.app.AppCompatDelegate;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.VersionUtils;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.widget.Toolbar;
+import android.support.v7.view.menu.MenuPresenter;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.view.Menu;
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
index 7a84b08..e0e1a83 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
@@ -26,16 +26,15 @@
 import android.support.v4.view.ActionProvider;
 import android.support.v4.view.GravityCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.transition.ActionBarTransition;
-import android.support.v7.internal.view.ActionBarPolicy;
-import android.support.v7.internal.view.menu.ActionMenuItemView;
-import android.support.v7.internal.view.menu.BaseMenuPresenter;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.TintImageView;
+import android.support.v7.transition.ActionBarTransition;
+import android.support.v7.view.ActionBarPolicy;
+import android.support.v7.view.menu.ActionMenuItemView;
+import android.support.v7.view.menu.BaseMenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.view.menu.SubMenuBuilder;
 import android.util.SparseBooleanArray;
 import android.view.MenuItem;
 import android.view.SoundEffectConstants;
@@ -47,10 +46,8 @@
 
 /**
  * MenuPresenter for building action menus as seen in the action bar and action modes.
- *
- * @hide
  */
-public class ActionMenuPresenter extends BaseMenuPresenter
+class ActionMenuPresenter extends BaseMenuPresenter
         implements ActionProvider.SubUiVisibilityListener {
 
     private static final String TAG = "ActionMenuPresenter";
@@ -606,7 +603,8 @@
         };
     }
 
-    private class OverflowMenuButton extends TintImageView implements ActionMenuView.ActionMenuChildView {
+    private class OverflowMenuButton extends AppCompatImageView
+            implements ActionMenuView.ActionMenuChildView {
         private final float[] mTempPts = new float[2];
 
         public OverflowMenuButton(Context context) {
@@ -704,7 +702,9 @@
         @Override
         public void onDismiss() {
             super.onDismiss();
-            mMenu.close();
+            if (mMenu != null) {
+                mMenu.close();
+            }
             mOverflowPopup = null;
         }
     }
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
index 0e47283..9919fec 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
@@ -21,12 +21,11 @@
 import android.os.Build;
 import android.support.annotation.Nullable;
 import android.support.annotation.StyleRes;
-import android.support.v7.internal.view.menu.ActionMenuItemView;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.widget.ViewUtils;
+import android.support.v7.view.menu.ActionMenuItemView;
+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.util.AttributeSet;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java b/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java
rename to v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
index 88dbf12..af405eb 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -87,10 +87,8 @@
  * <p>
  * <strong>Note:</strong> This class is thread safe.
  * </p>
- *
- * @hide
  */
-public class ActivityChooserModel extends DataSetObservable {
+class ActivityChooserModel extends DataSetObservable {
 
     /**
      * Client that utilizes an {@link ActivityChooserModel}.
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserView.java b/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserView.java
rename to v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
index 9931afb..3ea3a2e 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.Intent;
@@ -27,8 +27,6 @@
 import android.support.v4.view.ActionProvider;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.widget.LinearLayoutCompat;
-import android.support.v7.widget.ListPopupWindow;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
index a057677..4df02a0 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
@@ -24,9 +24,6 @@
 import android.support.annotation.Nullable;
 import android.support.v4.view.TintableBackgroundView;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
 import android.util.AttributeSet;
 import android.widget.AutoCompleteTextView;
 
@@ -52,7 +49,7 @@
             android.R.attr.popupBackground
     };
 
-    private TintManager mTintManager;
+    private AppCompatDrawableManager mDrawableManager;
     private AppCompatBackgroundHelper mBackgroundTintHelper;
     private AppCompatTextHelper mTextHelper;
 
@@ -67,25 +64,27 @@
     public AppCompatAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
 
+        mDrawableManager = AppCompatDrawableManager.get();
+
         TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
                 TINT_ATTRS, defStyleAttr, 0);
-        mTintManager = a.getTintManager();
         if (a.hasValue(0)) {
             setDropDownBackgroundDrawable(a.getDrawable(0));
         }
         a.recycle();
 
-        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
         mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
 
-        mTextHelper = new AppCompatTextHelper(this);
+        mTextHelper = AppCompatTextHelper.create(this);
         mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+        mTextHelper.applyCompoundDrawablesTints();
     }
 
     @Override
     public void setDropDownBackgroundResource(@DrawableRes int resId) {
-        if (mTintManager != null) {
-            setDropDownBackgroundDrawable(mTintManager.getDrawable(resId));
+        if (mDrawableManager != null) {
+            setDropDownBackgroundDrawable(mDrawableManager.getDrawable(getContext(), resId));
         } else {
             super.setDropDownBackgroundResource(resId);
         }
@@ -165,6 +164,9 @@
         if (mBackgroundTintHelper != null) {
             mBackgroundTintHelper.applySupportBackgroundTint();
         }
+        if (mTextHelper != null) {
+            mTextHelper.applyCompoundDrawablesTints();
+        }
     }
 
     @Override
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
index 7494b24..90d823c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
@@ -23,22 +23,20 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.graphics.drawable.DrawableUtils;
-import android.support.v7.internal.widget.TintInfo;
-import android.support.v7.internal.widget.TintManager;
 import android.util.AttributeSet;
 import android.view.View;
 
 class AppCompatBackgroundHelper {
 
     private final View mView;
-    private final TintManager mTintManager;
+    private final AppCompatDrawableManager mDrawableManager;
 
     private TintInfo mInternalBackgroundTint;
     private TintInfo mBackgroundTint;
 
-    AppCompatBackgroundHelper(View view, TintManager tintManager) {
+    AppCompatBackgroundHelper(View view, AppCompatDrawableManager drawableManager) {
         mView = view;
-        mTintManager = tintManager;
+        mDrawableManager = drawableManager;
     }
 
     void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
@@ -46,7 +44,7 @@
                 R.styleable.ViewBackgroundHelper, defStyleAttr, 0);
         try {
             if (a.hasValue(R.styleable.ViewBackgroundHelper_android_background)) {
-                ColorStateList tint = mTintManager.getTintList(
+                ColorStateList tint = mDrawableManager.getTintList(mView.getContext(),
                         a.getResourceId(R.styleable.ViewBackgroundHelper_android_background, -1));
                 if (tint != null) {
                     setInternalBackgroundTint(tint);
@@ -69,7 +67,9 @@
 
     void onSetBackgroundResource(int resId) {
         // Update the default background tint
-        setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+        setInternalBackgroundTint(mDrawableManager != null
+                ? mDrawableManager.getTintList(mView.getContext(), resId)
+                : null);
     }
 
     void onSetBackgroundDrawable(Drawable background) {
@@ -106,11 +106,14 @@
     }
 
     void applySupportBackgroundTint() {
-        if (mView.getBackground() != null) {
+        final Drawable background = mView.getBackground();
+        if (background != null) {
             if (mBackgroundTint != null) {
-                TintManager.tintViewBackground(mView, mBackgroundTint);
+                AppCompatDrawableManager
+                        .tintDrawable(background, mBackgroundTint, mView.getDrawableState());
             } else if (mInternalBackgroundTint != null) {
-                TintManager.tintViewBackground(mView, mInternalBackgroundTint);
+                AppCompatDrawableManager.tintDrawable(background, mInternalBackgroundTint,
+                        mView.getDrawableState());
             }
         }
     }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
index 91d69c8..15dacb0 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
@@ -24,8 +24,6 @@
 import android.support.annotation.Nullable;
 import android.support.v4.view.TintableBackgroundView;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.text.AllCapsTransformationMethod;
-import android.support.v7.internal.widget.TintManager;
 import android.util.AttributeSet;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -48,7 +46,7 @@
  */
 public class AppCompatButton extends Button implements TintableBackgroundView {
 
-    private final TintManager mTintManager;
+    private final AppCompatDrawableManager mDrawableManager;
     private final AppCompatBackgroundHelper mBackgroundTintHelper;
     private final AppCompatTextHelper mTextHelper;
 
@@ -63,12 +61,13 @@
     public AppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        mTintManager = TintManager.get(getContext());
-        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+        mDrawableManager = AppCompatDrawableManager.get();
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
         mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
 
-        mTextHelper = new AppCompatTextHelper(this);
+        mTextHelper = AppCompatTextHelper.create(this);
         mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+        mTextHelper.applyCompoundDrawablesTints();
     }
 
     @Override
@@ -145,6 +144,9 @@
         if (mBackgroundTintHelper != null) {
             mBackgroundTintHelper.applySupportBackgroundTint();
         }
+        if (mTextHelper != null) {
+            mTextHelper.applyCompoundDrawablesTints();
+        }
     }
 
     @Override
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
index 1ad2c77..4a6ecbe 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
@@ -25,7 +25,6 @@
 import android.support.v4.content.ContextCompat;
 import android.support.v4.widget.TintableCompoundButton;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
 import android.util.AttributeSet;
 import android.widget.CheckBox;
 
@@ -44,7 +43,7 @@
  */
 public class AppCompatCheckBox extends CheckBox implements TintableCompoundButton {
 
-    private TintManager mTintManager;
+    private AppCompatDrawableManager mDrawableManager;
     private AppCompatCompoundButtonHelper mCompoundButtonHelper;
 
     public AppCompatCheckBox(Context context) {
@@ -57,8 +56,8 @@
 
     public AppCompatCheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mTintManager = TintManager.get(context);
-        mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager);
+        mDrawableManager = AppCompatDrawableManager.get();
+        mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mDrawableManager);
         mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
     }
 
@@ -72,8 +71,8 @@
 
     @Override
     public void setButtonDrawable(@DrawableRes int resId) {
-        setButtonDrawable(mTintManager != null
-                ? mTintManager.getDrawable(resId)
+        setButtonDrawable(mDrawableManager != null
+                ? mDrawableManager.getDrawable(getContext(), resId)
                 : ContextCompat.getDrawable(getContext(), resId));
     }
 
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
index 4776b83..29c877c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 import android.support.annotation.DrawableRes;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
 import android.util.AttributeSet;
 import android.widget.CheckedTextView;
 
@@ -35,7 +33,8 @@
             android.R.attr.checkMark
     };
 
-    private TintManager mTintManager;
+    private AppCompatDrawableManager mDrawableManager;
+    private AppCompatTextHelper mTextHelper;
 
     public AppCompatCheckedTextView(Context context) {
         this(context, null);
@@ -48,23 +47,40 @@
     public AppCompatCheckedTextView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        if (TintManager.SHOULD_BE_USED) {
-            TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
-                    TINT_ATTRS, defStyleAttr, 0);
-            setCheckMarkDrawable(a.getDrawable(0));
-            a.recycle();
+        mTextHelper = AppCompatTextHelper.create(this);
+        mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+        mTextHelper.applyCompoundDrawablesTints();
 
-            mTintManager = a.getTintManager();
-        }
+        mDrawableManager = AppCompatDrawableManager.get();
+
+        TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
+                TINT_ATTRS, defStyleAttr, 0);
+        setCheckMarkDrawable(a.getDrawable(0));
+        a.recycle();
     }
 
     @Override
     public void setCheckMarkDrawable(@DrawableRes int resId) {
-        if (mTintManager != null) {
-            setCheckMarkDrawable(mTintManager.getDrawable(resId));
+        if (mDrawableManager != null) {
+            setCheckMarkDrawable(mDrawableManager.getDrawable(getContext(), resId));
         } else {
             super.setCheckMarkDrawable(resId);
         }
     }
 
+    @Override
+    public void setTextAppearance(Context context, int resId) {
+        super.setTextAppearance(context, resId);
+        if (mTextHelper != null) {
+            mTextHelper.onSetTextAppearance(context, resId);
+        }
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mTextHelper != null) {
+            mTextHelper.applyCompoundDrawablesTints();
+        }
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
index 20c3667..ad3e6d3 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
@@ -26,14 +26,13 @@
 import android.support.v4.widget.CompoundButtonCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.graphics.drawable.DrawableUtils;
-import android.support.v7.internal.widget.TintManager;
 import android.util.AttributeSet;
 import android.widget.CompoundButton;
 
 class AppCompatCompoundButtonHelper {
 
     private final CompoundButton mView;
-    private final TintManager mTintManager;
+    private final AppCompatDrawableManager mDrawableManager;
 
     private ColorStateList mButtonTintList = null;
     private PorterDuff.Mode mButtonTintMode = null;
@@ -49,9 +48,9 @@
         void setButtonDrawable(Drawable buttonDrawable);
     }
 
-    AppCompatCompoundButtonHelper(CompoundButton view, TintManager tintManager) {
+    AppCompatCompoundButtonHelper(CompoundButton view, AppCompatDrawableManager drawableManager) {
         mView = view;
-        mTintManager = tintManager;
+        mDrawableManager = drawableManager;
     }
 
     void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
@@ -62,7 +61,8 @@
                 final int resourceId = a.getResourceId(
                         R.styleable.CompoundButton_android_button, 0);
                 if (resourceId != 0) {
-                    mView.setButtonDrawable(mTintManager.getDrawable(resourceId));
+                    mView.setButtonDrawable(
+                            mDrawableManager.getDrawable(mView.getContext(), resourceId));
                 }
             }
             if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
similarity index 65%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
rename to v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index d926e17..4fcaf13 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -22,8 +22,14 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.graphics.drawable.InsetDrawable;
 import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
+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.graphics.ColorUtils;
 import android.support.v4.graphics.drawable.DrawableCompat;
@@ -31,27 +37,45 @@
 import android.support.v7.appcompat.R;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.View;
 
-import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.WeakHashMap;
 
-import static android.support.v7.internal.widget.ThemeUtils.getDisabledThemeAttrColor;
-import static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColor;
-import static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColorStateList;
+import static android.support.v7.widget.ThemeUtils.getDisabledThemeAttrColor;
+import static android.support.v7.widget.ThemeUtils.getThemeAttrColor;
+import static android.support.v7.widget.ThemeUtils.getThemeAttrColorStateList;
 
 /**
  * @hide
  */
-public final class TintManager {
+public final class AppCompatDrawableManager {
 
-    public static final boolean SHOULD_BE_USED = Build.VERSION.SDK_INT < 21;
+    public interface InflateDelegate {
+        /**
+         * Allows custom inflation of a drawable resource.
+         *
+         * @param context Context to inflate/create with
+         * @param resId Resource ID of the drawable
+         * @return the created drawable, or {@code null} to leave inflation to
+         * AppCompatDrawableManager.
+         */
+        @Nullable
+        Drawable onInflateDrawable(@NonNull Context context, @DrawableRes int resId);
+    }
 
     private static final String TAG = "TintManager";
     private static final boolean DEBUG = false;
     private static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN;
 
-    private static final WeakHashMap<Context, TintManager> INSTANCE_CACHE = new WeakHashMap<>();
+    private static AppCompatDrawableManager INSTANCE;
+
+    public static AppCompatDrawableManager get() {
+        if (INSTANCE == null) {
+            INSTANCE = new AppCompatDrawableManager();
+        }
+        return INSTANCE;
+    }
+
     private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6);
 
     /**
@@ -131,46 +155,27 @@
             R.drawable.abc_btn_radio_material
     };
 
-    private final WeakReference<Context> mContextRef;
-    private SparseArray<ColorStateList> mTintLists;
-    private ColorStateList mDefaultColorStateList;
+    private WeakHashMap<Context, SparseArray<ColorStateList>> mTintLists;
+    private ArrayList<InflateDelegate> mDelegates;
 
-    /**
-     * A helper method to get a {@link TintManager} and then call {@link #getDrawable(int)}.
-     * This method should not be used routinely.
-     */
-    public static Drawable getDrawable(Context context, int resId) {
-        if (isInTintList(resId)) {
-            return TintManager.get(context).getDrawable(resId);
-        } else {
-            return ContextCompat.getDrawable(context, resId);
+    public Drawable getDrawable(@NonNull Context context, @DrawableRes int resId) {
+        return getDrawable(context, resId, false);
+    }
+
+    public Drawable getDrawable(@NonNull Context context, @DrawableRes int resId,
+            boolean failIfNotKnown) {
+        // Let the InflateDelegates have a go first
+        if (mDelegates != null) {
+            for (int i = 0, count = mDelegates.size(); i < count; i++) {
+                final InflateDelegate delegate = mDelegates.get(i);
+                final Drawable result = delegate.onInflateDrawable(context, resId);
+                if (result != null) {
+                    return result;
+                }
+            }
         }
-    }
 
-    /**
-     * Get a {@link android.support.v7.internal.widget.TintManager} instance.
-     */
-    public static TintManager get(Context context) {
-        TintManager tm = INSTANCE_CACHE.get(context);
-        if (tm == null) {
-            tm = new TintManager(context);
-            INSTANCE_CACHE.put(context, tm);
-        }
-        return tm;
-    }
-
-    private TintManager(Context context) {
-        mContextRef = new WeakReference<>(context);
-    }
-
-    public Drawable getDrawable(int resId) {
-        return getDrawable(resId, false);
-    }
-
-    public Drawable getDrawable(int resId, boolean failIfNotKnown) {
-        final Context context = mContextRef.get();
-        if (context == null) return null;
-
+        // The delegates failed so we'll carry on
         Drawable drawable = ContextCompat.getDrawable(context, resId);
 
         if (drawable != null) {
@@ -179,7 +184,7 @@
                 drawable = drawable.mutate();
             }
 
-            final ColorStateList tintList = getTintList(resId);
+            final ColorStateList tintList = getTintList(context, resId);
             if (tintList != null) {
                 // First wrap the Drawable and set the tint list
                 drawable = DrawableCompat.wrap(drawable);
@@ -191,13 +196,21 @@
                     DrawableCompat.setTintMode(drawable, tintMode);
                 }
             } else if (resId == R.drawable.abc_cab_background_top_material) {
-                return new LayerDrawable(new Drawable[] {
-                        getDrawable(R.drawable.abc_cab_background_internal_bg),
-                        getDrawable(R.drawable.abc_cab_background_top_mtrl_alpha)
+                return new LayerDrawable(new Drawable[]{
+                        getDrawable(context, R.drawable.abc_cab_background_internal_bg),
+                        getDrawable(context, R.drawable.abc_cab_background_top_mtrl_alpha)
                 });
+            } else if (resId == R.drawable.abc_seekbar_track_material) {
+                LayerDrawable ld = (LayerDrawable) drawable;
+                setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.background),
+                        getThemeAttrColor(context, R.attr.colorControlNormal), DEFAULT_MODE);
+                setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.secondaryProgress),
+                        getThemeAttrColor(context, R.attr.colorControlNormal), DEFAULT_MODE);
+                setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.progress),
+                        getThemeAttrColor(context, R.attr.colorControlActivated), DEFAULT_MODE);
             } else {
-                final boolean usedColorFilter = tintDrawableUsingColorFilter(resId, drawable);
-                if (!usedColorFilter && failIfNotKnown) {
+                final boolean tinted = tintDrawableUsingColorFilter(context, resId, drawable);
+                if (!tinted && failIfNotKnown) {
                     // If we didn't tint using a ColorFilter, and we're set to fail if we don't
                     // know the id, return null
                     drawable = null;
@@ -207,10 +220,8 @@
         return drawable;
     }
 
-    public final boolean tintDrawableUsingColorFilter(final int resId, Drawable drawable) {
-        final Context context = mContextRef.get();
-        if (context == null) return false;
-
+    public final boolean tintDrawableUsingColorFilter(@NonNull Context context,
+            @DrawableRes final int resId, @NonNull Drawable drawable) {
         PorterDuff.Mode tintMode = DEFAULT_MODE;
         boolean colorAttrSet = false;
         int colorAttr = 0;
@@ -249,6 +260,21 @@
         return false;
     }
 
+    public void addDelegate(@NonNull InflateDelegate delegate) {
+        if (mDelegates == null) {
+            mDelegates = new ArrayList<>();
+        }
+        if (!mDelegates.contains(delegate)) {
+            mDelegates.add(delegate);
+        }
+    }
+
+    public void removeDelegate(@NonNull InflateDelegate delegate) {
+        if (mDelegates != null) {
+            mDelegates.remove(delegate);
+        }
+    }
+
     private static boolean arrayContains(int[] array, int value) {
         for (int id : array) {
             if (id == value) {
@@ -258,16 +284,6 @@
         return false;
     }
 
-    private static boolean isInTintList(int drawableId) {
-        return arrayContains(TINT_COLOR_CONTROL_NORMAL, drawableId) ||
-                arrayContains(COLORFILTER_TINT_COLOR_CONTROL_NORMAL, drawableId) ||
-                arrayContains(COLORFILTER_COLOR_CONTROL_ACTIVATED, drawableId) ||
-                arrayContains(TINT_COLOR_CONTROL_STATE_LIST, drawableId) ||
-                arrayContains(COLORFILTER_COLOR_BACKGROUND_MULTIPLY, drawableId) ||
-                arrayContains(TINT_CHECKABLE_BUTTON_LIST, drawableId) ||
-                drawableId == R.drawable.abc_cab_background_top_material;
-    }
-
     final PorterDuff.Mode getTintMode(final int resId) {
         PorterDuff.Mode mode = null;
 
@@ -278,12 +294,9 @@
         return mode;
     }
 
-    public final ColorStateList getTintList(int resId) {
-        final Context context = mContextRef.get();
-        if (context == null) return null;
-
+    public final ColorStateList getTintList(@NonNull Context context, @DrawableRes int resId) {
         // Try the cache first (if it exists)
-        ColorStateList tint = mTintLists != null ? mTintLists.get(resId) : null;
+        ColorStateList tint = getTintListFromCache(context, resId);
 
         if (tint == null) {
             // ...if the cache did not contain a color state list, try and create one
@@ -304,71 +317,85 @@
             } else if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) {
                 tint = getThemeAttrColorStateList(context, R.attr.colorControlNormal);
             } else if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) {
-                tint = getDefaultColorStateList(context);
+                tint = createDefaultColorStateList(context);
             } else if (arrayContains(TINT_CHECKABLE_BUTTON_LIST, resId)) {
                 tint = createCheckableButtonColorStateList(context);
+            } else if (resId == R.drawable.abc_seekbar_thumb_material) {
+                tint = createSeekbarThumbColorStateList(context);
             }
 
             if (tint != null) {
-                if (mTintLists == null) {
-                    // If our tint list cache hasn't been set up yet, create it
-                    mTintLists = new SparseArray<>();
-                }
-                // Add any newly created ColorStateList to the cache
-                mTintLists.append(resId, tint);
+                addTintListToCache(context, resId, tint);
             }
         }
         return tint;
     }
 
-    private ColorStateList getDefaultColorStateList(Context context) {
-        if (mDefaultColorStateList == null) {
-            /**
-             * Generate the default color state list which uses the colorControl attributes.
-             * Order is important here. The default enabled state needs to go at the bottom.
-             */
-
-            final int colorControlNormal = getThemeAttrColor(context, R.attr.colorControlNormal);
-            final int colorControlActivated = getThemeAttrColor(context,
-                    R.attr.colorControlActivated);
-
-            final int[][] states = new int[7][];
-            final int[] colors = new int[7];
-            int i = 0;
-
-            // Disabled state
-            states[i] = ThemeUtils.DISABLED_STATE_SET;
-            colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal);
-            i++;
-
-            states[i] = ThemeUtils.FOCUSED_STATE_SET;
-            colors[i] = colorControlActivated;
-            i++;
-
-            states[i] = ThemeUtils.ACTIVATED_STATE_SET;
-            colors[i] = colorControlActivated;
-            i++;
-
-            states[i] = ThemeUtils.PRESSED_STATE_SET;
-            colors[i] = colorControlActivated;
-            i++;
-
-            states[i] = ThemeUtils.CHECKED_STATE_SET;
-            colors[i] = colorControlActivated;
-            i++;
-
-            states[i] = ThemeUtils.SELECTED_STATE_SET;
-            colors[i] = colorControlActivated;
-            i++;
-
-            // Default enabled state
-            states[i] = ThemeUtils.EMPTY_STATE_SET;
-            colors[i] = colorControlNormal;
-            i++;
-
-            mDefaultColorStateList = new ColorStateList(states, colors);
+    private ColorStateList getTintListFromCache(@NonNull Context context, @DrawableRes int resId) {
+        if (mTintLists != null) {
+            final SparseArray<ColorStateList> tints = mTintLists.get(context);
+            return tints != null ? tints.get(resId) : null;
         }
-        return mDefaultColorStateList;
+        return null;
+    }
+
+    private void addTintListToCache(@NonNull Context context, @DrawableRes int resId,
+            @NonNull ColorStateList tintList) {
+        if (mTintLists == null) {
+            mTintLists = new WeakHashMap<>();
+        }
+        SparseArray<ColorStateList> themeTints = mTintLists.get(context);
+        if (themeTints == null) {
+            themeTints = new SparseArray<>();
+            mTintLists.put(context, themeTints);
+        }
+        themeTints.append(resId, tintList);
+    }
+
+    private ColorStateList createDefaultColorStateList(Context context) {
+        /**
+         * Generate the default color state list which uses the colorControl attributes.
+         * Order is important here. The default enabled state needs to go at the bottom.
+         */
+
+        final int colorControlNormal = getThemeAttrColor(context, R.attr.colorControlNormal);
+        final int colorControlActivated = getThemeAttrColor(context, R.attr.colorControlActivated);
+
+        final int[][] states = new int[7][];
+        final int[] colors = new int[7];
+        int i = 0;
+
+        // Disabled state
+        states[i] = ThemeUtils.DISABLED_STATE_SET;
+        colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal);
+        i++;
+
+        states[i] = ThemeUtils.FOCUSED_STATE_SET;
+        colors[i] = colorControlActivated;
+        i++;
+
+        states[i] = ThemeUtils.ACTIVATED_STATE_SET;
+        colors[i] = colorControlActivated;
+        i++;
+
+        states[i] = ThemeUtils.PRESSED_STATE_SET;
+        colors[i] = colorControlActivated;
+        i++;
+
+        states[i] = ThemeUtils.CHECKED_STATE_SET;
+        colors[i] = colorControlActivated;
+        i++;
+
+        states[i] = ThemeUtils.SELECTED_STATE_SET;
+        colors[i] = colorControlActivated;
+        i++;
+
+        // Default enabled state
+        states[i] = ThemeUtils.EMPTY_STATE_SET;
+        colors[i] = colorControlNormal;
+        i++;
+
+        return new ColorStateList(states, colors);
     }
 
     private ColorStateList createCheckableButtonColorStateList(Context context) {
@@ -541,6 +568,23 @@
         return new ColorStateList(states, colors);
     }
 
+    private ColorStateList createSeekbarThumbColorStateList(Context context) {
+        final int[][] states = new int[2][];
+        final int[] colors = new int[2];
+        int i = 0;
+
+        // Disabled state
+        states[i] = ThemeUtils.DISABLED_STATE_SET;
+        colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlActivated);
+        i++;
+
+        states[i] = ThemeUtils.EMPTY_STATE_SET;
+        colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated);
+        i++;
+
+        return new ColorStateList(states, colors);
+    }
+
     private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> {
 
         public ColorFilterLruCache(int maxSize) {
@@ -563,22 +607,50 @@
         }
     }
 
-    public static void tintViewBackground(View view, TintInfo tint) {
-        final Drawable background = view.getBackground();
-        if (tint.mHasTintList || tint.mHasTintMode) {
-            background.setColorFilter(createTintFilter(
-                    tint.mHasTintList ? tint.mTintList : null,
-                    tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE,
-                    view.getDrawableState()));
-        } else {
-            background.clearColorFilter();
+    public static void tintDrawable(Drawable drawable, TintInfo tint, int[] state) {
+        if (shouldMutateBackground(drawable) && drawable.mutate() != drawable) {
+            Log.d(TAG, "Mutated drawable is not the same instance as the input.");
+            return;
         }
 
-        if (Build.VERSION.SDK_INT <= 10) {
-            // On Gingerbread, GradientDrawable does not invalidate itself when it's ColorFilter
-            // has changed, so we need to force an invalidation
-            view.invalidate();
+        if (tint.mHasTintList || tint.mHasTintMode) {
+            drawable.setColorFilter(createTintFilter(
+                    tint.mHasTintList ? tint.mTintList : null,
+                    tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE,
+                    state));
+        } else {
+            drawable.clearColorFilter();
         }
+
+        if (Build.VERSION.SDK_INT <= 23) {
+            // Pre-v23 there is no guarantee that a state change will invoke an invalidation,
+            // so we force it ourselves
+            drawable.invalidateSelf();
+        }
+    }
+
+    private static boolean shouldMutateBackground(Drawable drawable) {
+        if (drawable instanceof LayerDrawable) {
+            return Build.VERSION.SDK_INT >= 16;
+        } else if (drawable instanceof InsetDrawable) {
+            return Build.VERSION.SDK_INT >= 14;
+        } else if (drawable instanceof StateListDrawable) {
+            // StateListDrawable has a bug in mutate() on API 7
+            return Build.VERSION.SDK_INT >= 8;
+        } else if (drawable instanceof DrawableContainer) {
+            // If we have a DrawableContainer, let's traverse it's child array
+            final Drawable.ConstantState state = drawable.getConstantState();
+            if (state instanceof DrawableContainer.DrawableContainerState) {
+                final DrawableContainer.DrawableContainerState containerState =
+                        (DrawableContainer.DrawableContainerState) state;
+                for (Drawable child : containerState.getChildren()) {
+                    if (!shouldMutateBackground(child)) {
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
     }
 
     private static PorterDuffColorFilter createTintFilter(ColorStateList tint,
@@ -590,7 +662,7 @@
         return getPorterDuffColorFilter(color, tintMode);
     }
 
-    private static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
+    public static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
         // First, lets see if the cache already contains the color filter
         PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);
 
@@ -602,4 +674,8 @@
 
         return filter;
     }
+
+    private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) {
+        d.setColorFilter(getPorterDuffColorFilter(color, mode == null ? DEFAULT_MODE : mode));
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java b/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
index 885fd6d..d690545c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
@@ -24,8 +24,6 @@
 import android.support.annotation.Nullable;
 import android.support.v4.view.TintableBackgroundView;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintManager;
 import android.util.AttributeSet;
 import android.widget.EditText;
 
@@ -46,7 +44,7 @@
  */
 public class AppCompatEditText extends EditText implements TintableBackgroundView {
 
-    private TintManager mTintManager;
+    private AppCompatDrawableManager mDrawableManager;
     private AppCompatBackgroundHelper mBackgroundTintHelper;
     private AppCompatTextHelper mTextHelper;
 
@@ -61,12 +59,13 @@
     public AppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {
         super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
 
-        mTintManager = TintManager.get(getContext());
-        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+        mDrawableManager = AppCompatDrawableManager.get();
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
         mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
 
-        mTextHelper = new AppCompatTextHelper(this);
+        mTextHelper = AppCompatTextHelper.create(this);
         mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+        mTextHelper.applyCompoundDrawablesTints();
     }
 
     @Override
@@ -143,6 +142,9 @@
         if (mBackgroundTintHelper != null) {
             mBackgroundTintHelper.applySupportBackgroundTint();
         }
+        if (mTextHelper != null) {
+            mTextHelper.applyCompoundDrawablesTints();
+        }
     }
 
     @Override
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
new file mode 100644
index 0000000..18c07c9
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+
+/**
+ * A {@link ImageButton} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ *     <li>Allows dynamic tint of it background via the background tint methods in
+ *     {@link android.support.v4.view.ViewCompat}.</li>
+ *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ *     {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.ImageButton} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatImageButton extends ImageButton implements TintableBackgroundView {
+
+    private AppCompatBackgroundHelper mBackgroundTintHelper;
+    private AppCompatImageHelper mImageHelper;
+
+    public AppCompatImageButton(Context context) {
+        this(context, null);
+    }
+
+    public AppCompatImageButton(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.imageButtonStyle);
+    }
+
+    public AppCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
+
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, drawableManager);
+        mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+        mImageHelper = new AppCompatImageHelper(this, drawableManager);
+        mImageHelper.loadFromAttributes(attrs, defStyleAttr);
+    }
+
+    @Override
+    public void setImageResource(@DrawableRes int resId) {
+        // Intercept this call and instead retrieve the Drawable via the image helper
+        mImageHelper.setImageResource(resId);
+    }
+
+    @Override
+    public void setBackgroundResource(@DrawableRes int resId) {
+        super.setBackgroundResource(resId);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundResource(resId);
+        }
+    }
+
+    @Override
+    public void setBackgroundDrawable(Drawable background) {
+        super.setBackgroundDrawable(background);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundDrawable(background);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public ColorStateList getSupportBackgroundTintList() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public PorterDuff.Mode getSupportBackgroundTintMode() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.applySupportBackgroundTint();
+        }
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java
new file mode 100644
index 0000000..f6e5bae
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+class AppCompatImageHelper {
+
+    private static final int[] VIEW_ATTRS = {android.R.attr.src};
+
+    private final ImageView mView;
+    private final AppCompatDrawableManager mDrawableManager;
+
+    AppCompatImageHelper(ImageView view, AppCompatDrawableManager drawableManager) {
+        mView = view;
+        mDrawableManager = drawableManager;
+    }
+
+    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+                VIEW_ATTRS, defStyleAttr, 0);
+        try {
+            if (a.hasValue(0)) {
+                mView.setImageDrawable(a.getDrawable(0));
+            }
+        } finally {
+            a.recycle();
+        }
+    }
+
+    void setImageResource(int resId) {
+        if (resId != 0) {
+            mView.setImageDrawable(mDrawableManager != null
+                    ? mDrawableManager.getDrawable(mView.getContext(), resId)
+                    : ContextCompat.getDrawable(mView.getContext(), resId));
+        } else {
+            mView.setImageDrawable(null);
+        }
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
new file mode 100644
index 0000000..0d85121
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * A {@link ImageView} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ *     <li>Allows dynamic tint of it background via the background tint methods in
+ *     {@link android.support.v4.view.ViewCompat}.</li>
+ *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ *     {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.ImageView} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatImageView extends ImageView implements TintableBackgroundView {
+
+    private AppCompatBackgroundHelper mBackgroundTintHelper;
+    private AppCompatImageHelper mImageHelper;
+
+    public AppCompatImageView(Context context) {
+        this(context, null);
+    }
+
+    public AppCompatImageView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AppCompatImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
+
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, drawableManager);
+        mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+        mImageHelper = new AppCompatImageHelper(this, drawableManager);
+        mImageHelper.loadFromAttributes(attrs, defStyleAttr);
+    }
+
+    @Override
+    public void setImageResource(@DrawableRes int resId) {
+        // Intercept this call and instead retrieve the Drawable via the image helper
+        mImageHelper.setImageResource(resId);
+    }
+
+    @Override
+    public void setBackgroundResource(@DrawableRes int resId) {
+        super.setBackgroundResource(resId);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundResource(resId);
+        }
+    }
+
+    @Override
+    public void setBackgroundDrawable(Drawable background) {
+        super.setBackgroundDrawable(background);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundDrawable(background);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public ColorStateList getSupportBackgroundTintList() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public PorterDuff.Mode getSupportBackgroundTintMode() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.applySupportBackgroundTint();
+        }
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
index 6f97adb..34cece6 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
@@ -24,9 +24,6 @@
 import android.support.annotation.Nullable;
 import android.support.v4.view.TintableBackgroundView;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
 import android.util.AttributeSet;
 import android.widget.MultiAutoCompleteTextView;
 
@@ -52,7 +49,7 @@
             android.R.attr.popupBackground
     };
 
-    private TintManager mTintManager;
+    private AppCompatDrawableManager mDrawableManager;
     private AppCompatBackgroundHelper mBackgroundTintHelper;
     private AppCompatTextHelper mTextHelper;
 
@@ -67,25 +64,27 @@
     public AppCompatMultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
 
+        mDrawableManager = AppCompatDrawableManager.get();
+
         TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
                 TINT_ATTRS, defStyleAttr, 0);
-        mTintManager = a.getTintManager();
         if (a.hasValue(0)) {
             setDropDownBackgroundDrawable(a.getDrawable(0));
         }
         a.recycle();
 
-        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
         mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
 
-        mTextHelper = new AppCompatTextHelper(this);
+        mTextHelper = AppCompatTextHelper.create(this);
         mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+        mTextHelper.applyCompoundDrawablesTints();
     }
 
     @Override
     public void setDropDownBackgroundResource(@DrawableRes int resId) {
-        if (mTintManager != null) {
-            setDropDownBackgroundDrawable(mTintManager.getDrawable(resId));
+        if (mDrawableManager != null) {
+            setDropDownBackgroundDrawable(mDrawableManager.getDrawable(getContext(), resId));
         } else {
             super.setDropDownBackgroundResource(resId);
         }
@@ -165,6 +164,9 @@
         if (mBackgroundTintHelper != null) {
             mBackgroundTintHelper.applySupportBackgroundTint();
         }
+        if (mTextHelper != null) {
+            mTextHelper.applyCompoundDrawablesTints();
+        }
     }
 
     @Override
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java b/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java
rename to v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
index d71d606..0cce845 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.annotation.TargetApi;
 import android.content.Context;
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java
new file mode 100644
index 0000000..209a6c2
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Shader;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ClipDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RoundRectShape;
+import android.graphics.drawable.shapes.Shape;
+import android.support.v4.graphics.drawable.DrawableWrapper;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.widget.ProgressBar;
+
+class AppCompatProgressBarHelper {
+
+    private static final int[] TINT_ATTRS = {
+            android.R.attr.indeterminateDrawable,
+            android.R.attr.progressDrawable
+    };
+
+    private final ProgressBar mView;
+    final AppCompatDrawableManager mDrawableManager;
+
+    private Bitmap mSampleTile;
+
+    AppCompatProgressBarHelper(ProgressBar view, AppCompatDrawableManager drawableManager) {
+        mView = view;
+        mDrawableManager = drawableManager;
+    }
+
+    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+                TINT_ATTRS, defStyleAttr, 0);
+
+        Drawable drawable = a.getDrawableIfKnown(0);
+        if (drawable != null) {
+            mView.setIndeterminateDrawable(tileifyIndeterminate(drawable));
+        }
+
+        drawable = a.getDrawableIfKnown(1);
+        if (drawable != null) {
+            mView.setProgressDrawable(tileify(drawable, false));
+        }
+
+        a.recycle();
+    }
+
+    /**
+     * Converts a drawable to a tiled version of itself. It will recursively
+     * traverse layer and state list drawables.
+     */
+    private Drawable tileify(Drawable drawable, boolean clip) {
+        if (drawable instanceof DrawableWrapper) {
+            Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
+            if (inner != null) {
+                inner = tileify(inner, clip);
+                ((DrawableWrapper) drawable).setWrappedDrawable(inner);
+            }
+        } else if (drawable instanceof LayerDrawable) {
+            LayerDrawable background = (LayerDrawable) drawable;
+            final int N = background.getNumberOfLayers();
+            Drawable[] outDrawables = new Drawable[N];
+
+            for (int i = 0; i < N; i++) {
+                int id = background.getId(i);
+                outDrawables[i] = tileify(background.getDrawable(i),
+                        (id == android.R.id.progress || id == android.R.id.secondaryProgress));
+            }
+            LayerDrawable newBg = new LayerDrawable(outDrawables);
+
+            for (int i = 0; i < N; i++) {
+                newBg.setId(i, background.getId(i));
+            }
+
+            return newBg;
+
+        } else if (drawable instanceof BitmapDrawable) {
+            final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
+            if (mSampleTile == null) {
+                mSampleTile = tileBitmap;
+            }
+
+            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
+            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
+                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
+            shapeDrawable.getPaint().setShader(bitmapShader);
+            return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
+                    ClipDrawable.HORIZONTAL) : shapeDrawable;
+        }
+
+        return drawable;
+    }
+
+    /**
+     * Convert a AnimationDrawable for use as a barberpole animation.
+     * Each frame of the animation is wrapped in a ClipDrawable and
+     * given a tiling BitmapShader.
+     */
+    private Drawable tileifyIndeterminate(Drawable drawable) {
+        if (drawable instanceof AnimationDrawable) {
+            AnimationDrawable background = (AnimationDrawable) drawable;
+            final int N = background.getNumberOfFrames();
+            AnimationDrawable newBg = new AnimationDrawable();
+            newBg.setOneShot(background.isOneShot());
+
+            for (int i = 0; i < N; i++) {
+                Drawable frame = tileify(background.getFrame(i), true);
+                frame.setLevel(10000);
+                newBg.addFrame(frame, background.getDuration(i));
+            }
+            newBg.setLevel(10000);
+            drawable = newBg;
+        }
+        return drawable;
+    }
+
+    private Shape getDrawableShape() {
+        final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
+        return new RoundRectShape(roundedCorners, null, null);
+    }
+
+    Bitmap getSampleTime() {
+        return mSampleTile;
+    }
+
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
index 0d928fc..3814a7e 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
@@ -25,7 +25,6 @@
 import android.support.v4.content.ContextCompat;
 import android.support.v4.widget.TintableCompoundButton;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
 import android.util.AttributeSet;
 import android.widget.RadioButton;
 
@@ -44,7 +43,7 @@
  */
 public class AppCompatRadioButton extends RadioButton implements TintableCompoundButton {
 
-    private TintManager mTintManager;
+    private AppCompatDrawableManager mDrawableManager;
     private AppCompatCompoundButtonHelper mCompoundButtonHelper;
 
     public AppCompatRadioButton(Context context) {
@@ -57,8 +56,8 @@
 
     public AppCompatRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mTintManager = TintManager.get(context);
-        mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager);
+        mDrawableManager = AppCompatDrawableManager.get();
+        mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mDrawableManager);
         mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
     }
 
@@ -72,8 +71,8 @@
 
     @Override
     public void setButtonDrawable(@DrawableRes int resId) {
-        setButtonDrawable(mTintManager != null
-                ? mTintManager.getDrawable(resId)
+        setButtonDrawable(mDrawableManager != null
+                ? mDrawableManager.getDrawable(getContext(), resId)
                 : ContextCompat.getDrawable(getContext(), resId));
     }
 
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
index 51811a8..8909265 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
@@ -18,23 +18,9 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Shader;
-import android.graphics.drawable.AnimationDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ClipDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RoundRectShape;
-import android.graphics.drawable.shapes.Shape;
-import android.support.v4.graphics.drawable.DrawableWrapper;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
 import android.util.AttributeSet;
-import android.view.Gravity;
 import android.widget.RatingBar;
 
 /**
@@ -45,12 +31,8 @@
  */
 public class AppCompatRatingBar extends RatingBar {
 
-    private static final int[] TINT_ATTRS = {
-            android.R.attr.indeterminateDrawable,
-            android.R.attr.progressDrawable
-    };
-
-    private Bitmap mSampleTile;
+    private AppCompatProgressBarHelper mAppCompatProgressBarHelper;
+    private AppCompatDrawableManager mDrawableManager;
 
     public AppCompatRatingBar(Context context) {
         this(context, null);
@@ -63,104 +45,19 @@
     public AppCompatRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        if (TintManager.SHOULD_BE_USED) {
-            TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
-                    TINT_ATTRS, defStyleAttr, 0);
+        mDrawableManager = AppCompatDrawableManager.get();
 
-            Drawable drawable = a.getDrawableIfKnown(0);
-            if (drawable != null) {
-                setIndeterminateDrawable(tileifyIndeterminate(drawable));
-            }
-
-            drawable = a.getDrawableIfKnown(1);
-            if (drawable != null) {
-                setProgressDrawable(tileify(drawable, false));
-            }
-
-            a.recycle();
-        }
-    }
-
-    /**
-     * Converts a drawable to a tiled version of itself. It will recursively
-     * traverse layer and state list drawables.
-     */
-    private Drawable tileify(Drawable drawable, boolean clip) {
-        if (drawable instanceof DrawableWrapper) {
-            Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
-            if (inner != null) {
-                inner = tileify(inner, clip);
-                ((DrawableWrapper) drawable).setWrappedDrawable(inner);
-            }
-        } else if (drawable instanceof LayerDrawable) {
-            LayerDrawable background = (LayerDrawable) drawable;
-            final int N = background.getNumberOfLayers();
-            Drawable[] outDrawables = new Drawable[N];
-
-            for (int i = 0; i < N; i++) {
-                int id = background.getId(i);
-                outDrawables[i] = tileify(background.getDrawable(i),
-                        (id == android.R.id.progress || id == android.R.id.secondaryProgress));
-            }
-            LayerDrawable newBg = new LayerDrawable(outDrawables);
-
-            for (int i = 0; i < N; i++) {
-                newBg.setId(i, background.getId(i));
-            }
-
-            return newBg;
-
-        } else if (drawable instanceof BitmapDrawable) {
-            final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
-            if (mSampleTile == null) {
-                mSampleTile = tileBitmap;
-            }
-
-            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
-            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
-                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
-            shapeDrawable.getPaint().setShader(bitmapShader);
-            return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
-                    ClipDrawable.HORIZONTAL) : shapeDrawable;
-        }
-
-        return drawable;
-    }
-
-    /**
-     * Convert a AnimationDrawable for use as a barberpole animation.
-     * Each frame of the animation is wrapped in a ClipDrawable and
-     * given a tiling BitmapShader.
-     */
-    private Drawable tileifyIndeterminate(Drawable drawable) {
-        if (drawable instanceof AnimationDrawable) {
-            AnimationDrawable background = (AnimationDrawable) drawable;
-            final int N = background.getNumberOfFrames();
-            AnimationDrawable newBg = new AnimationDrawable();
-            newBg.setOneShot(background.isOneShot());
-
-            for (int i = 0; i < N; i++) {
-                Drawable frame = tileify(background.getFrame(i), true);
-                frame.setLevel(10000);
-                newBg.addFrame(frame, background.getDuration(i));
-            }
-            newBg.setLevel(10000);
-            drawable = newBg;
-        }
-        return drawable;
-    }
-
-    private Shape getDrawableShape() {
-        final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
-        return new RoundRectShape(roundedCorners, null, null);
+        mAppCompatProgressBarHelper = new AppCompatProgressBarHelper(this, mDrawableManager);
+        mAppCompatProgressBarHelper.loadFromAttributes(attrs, defStyleAttr);
     }
 
     @Override
     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        if (mSampleTile != null) {
-            final int width = mSampleTile.getWidth() * getNumStars();
+        Bitmap sampleTile = mAppCompatProgressBarHelper.getSampleTime();
+        if (sampleTile != null) {
+            final int width = sampleTile.getWidth() * getNumStars();
             setMeasuredDimension(ViewCompat.resolveSizeAndState(width, widthMeasureSpec, 0),
                     getMeasuredHeight());
         }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
new file mode 100644
index 0000000..4f3ee05
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
@@ -0,0 +1,52 @@
+/*
+ * 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 android.support.v7.widget;
+
+import android.content.Context;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.widget.SeekBar;
+
+/**
+ * A {@link SeekBar} which supports compatible features on older version of the platform.
+ *
+ * <p>This will automatically be used when you use {@link SeekBar} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatSeekBar extends SeekBar {
+
+    private AppCompatSeekBarHelper mAppCompatSeekBarHelper;
+    private AppCompatDrawableManager mDrawableManager;
+
+    public AppCompatSeekBar(Context context) {
+        this(context, null);
+    }
+
+    public AppCompatSeekBar(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.seekBarStyle);
+    }
+
+    public AppCompatSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        mDrawableManager = AppCompatDrawableManager.get();
+
+        mAppCompatSeekBarHelper = new AppCompatSeekBarHelper(this, mDrawableManager);
+        mAppCompatSeekBarHelper.loadFromAttributes(attrs, defStyleAttr);
+    }
+
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
new file mode 100644
index 0000000..2af2acc
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.SeekBar;
+
+class AppCompatSeekBarHelper extends AppCompatProgressBarHelper {
+
+    private static final int[] TINT_ATTRS = {
+            android.R.attr.thumb
+    };
+
+    private final SeekBar mView;
+
+    AppCompatSeekBarHelper(SeekBar view, AppCompatDrawableManager drawableManager) {
+        super(view, drawableManager);
+        mView = view;
+    }
+
+    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+        super.loadFromAttributes(attrs, defStyleAttr);
+
+        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+                TINT_ATTRS, defStyleAttr, 0);
+        Drawable drawable = a.getDrawableIfKnown(0);
+        if (drawable != null) {
+            mView.setThumb(drawable);
+        }
+        a.recycle();
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
index 90985cdb..964ea76 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
@@ -30,10 +30,7 @@
 import android.support.v4.view.TintableBackgroundView;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ContextThemeWrapper;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
+import android.support.v7.view.ContextThemeWrapper;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -41,6 +38,7 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.PopupWindow;
@@ -77,7 +75,7 @@
     private static final int MODE_DROPDOWN = 1;
     private static final int MODE_THEME = -1;
 
-    private TintManager mTintManager;
+    private AppCompatDrawableManager mDrawableManager;
 
     private AppCompatBackgroundHelper mBackgroundTintHelper;
 
@@ -199,8 +197,8 @@
         TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
                 R.styleable.Spinner, defStyleAttr, 0);
 
-        mTintManager = a.getTintManager();
-        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+        mDrawableManager = AppCompatDrawableManager.get();
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
 
         if (popupTheme != null) {
             mPopupContext = new ContextThemeWrapper(context, popupTheme);
@@ -267,6 +265,15 @@
                 };
             }
         }
+
+        final CharSequence[] entries = a.getTextArray(R.styleable.Spinner_android_entries);
+        if (entries != null) {
+            final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<>(context,
+                    R.layout.support_simple_spinner_dropdown_item, entries);
+            adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
+            setAdapter(adapter);
+        }
+
         a.recycle();
 
         mPopupSet = true;
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
index 7a75e76..d8e7784 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
@@ -19,30 +19,59 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.text.AllCapsTransformationMethod;
-import android.support.v7.internal.widget.ThemeUtils;
+import android.support.v7.text.AllCapsTransformationMethod;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
 class AppCompatTextHelper {
 
-    private static final int[] VIEW_ATTRS = {android.R.attr.textAppearance};
+    static AppCompatTextHelper create(TextView textView) {
+        if (Build.VERSION.SDK_INT >= 17) {
+            return new AppCompatTextHelperV17(textView);
+        }
+        return new AppCompatTextHelper(textView);
+    }
+
+    private static final int[] VIEW_ATTRS = {android.R.attr.textAppearance,
+            android.R.attr.drawableLeft, android.R.attr.drawableTop,
+            android.R.attr.drawableRight, android.R.attr.drawableBottom };
     private static final int[] TEXT_APPEARANCE_ATTRS = {R.attr.textAllCaps};
 
-    private final TextView mView;
+    final TextView mView;
+
+    private TintInfo mDrawableLeftTint;
+    private TintInfo mDrawableTopTint;
+    private TintInfo mDrawableRightTint;
+    private TintInfo mDrawableBottomTint;
 
     AppCompatTextHelper(TextView view) {
         mView = view;
     }
 
     void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
-        Context context = mView.getContext();
+        final Context context = mView.getContext();
+        final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
 
         // First read the TextAppearance style id
         TypedArray a = context.obtainStyledAttributes(attrs, VIEW_ATTRS, defStyleAttr, 0);
         final int ap = a.getResourceId(0, -1);
+
+        // Now read the compound drawable and grab any tints
+        if (a.hasValue(1)) {
+            mDrawableLeftTint = createTintInfo(context, drawableManager, a.getResourceId(1, 0));
+        }
+        if (a.hasValue(2)) {
+            mDrawableTopTint = createTintInfo(context, drawableManager, a.getResourceId(2, 0));
+        }
+        if (a.hasValue(3)) {
+            mDrawableRightTint = createTintInfo(context, drawableManager, a.getResourceId(3, 0));
+        }
+        if (a.hasValue(4)) {
+            mDrawableBottomTint = createTintInfo(context, drawableManager, a.getResourceId(4, 0));
+        }
         a.recycle();
 
         // Now check TextAppearance's textAllCaps value
@@ -56,33 +85,10 @@
 
         // Now read the style's value
         a = context.obtainStyledAttributes(attrs, TEXT_APPEARANCE_ATTRS, defStyleAttr, 0);
-        if (a.hasValue(0)) {
-            setAllCaps(a.getBoolean(0, false));
+        if (a.getBoolean(0, false)) {
+            setAllCaps(true);
         }
         a.recycle();
-
-        final ColorStateList textColors = mView.getTextColors();
-        if (textColors != null && !textColors.isStateful()) {
-            // If we have a ColorStateList which isn't stateful, create one which includes
-            // a disabled state
-
-            final int disabledTextColor;
-            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
-                // Pre-Lollipop, we will use textColorSecondary with android:disabledAlpha
-                // applied
-                disabledTextColor = ThemeUtils.getDisabledThemeAttrColor(context,
-                        android.R.attr.textColorSecondary);
-            } else {
-                // With certain styles on Lollipop, there is a StateListAnimator which sets
-                // an alpha on the whole view, so we don't need to apply disabledAlpha to
-                // textColorSecondary
-                disabledTextColor = ThemeUtils.getThemeAttrColor(context,
-                        android.R.attr.textColorSecondary);
-            }
-
-            mView.setTextColor(ThemeUtils.createDisabledStateList(
-                    textColors.getDefaultColor(), disabledTextColor));
-        }
     }
 
     void onSetTextAppearance(Context context, int resId) {
@@ -98,4 +104,32 @@
                 ? new AllCapsTransformationMethod(mView.getContext())
                 : null);
     }
+
+    void applyCompoundDrawablesTints() {
+        if (mDrawableLeftTint != null || mDrawableTopTint != null ||
+                mDrawableRightTint != null || mDrawableBottomTint != null) {
+            final Drawable[] compoundDrawables = mView.getCompoundDrawables();
+            applyCompoundDrawableTint(compoundDrawables[0], mDrawableLeftTint);
+            applyCompoundDrawableTint(compoundDrawables[1], mDrawableTopTint);
+            applyCompoundDrawableTint(compoundDrawables[2], mDrawableRightTint);
+            applyCompoundDrawableTint(compoundDrawables[3], mDrawableBottomTint);
+        }
+    }
+
+    final void applyCompoundDrawableTint(Drawable drawable, TintInfo info) {
+        if (drawable != null && info != null) {
+            AppCompatDrawableManager.tintDrawable(drawable, info, mView.getDrawableState());
+        }
+    }
+
+    protected static TintInfo createTintInfo(Context context,
+            AppCompatDrawableManager drawableManager, int drawableId) {
+        final ColorStateList tintList = drawableManager.getTintList(context, drawableId);
+        if (tintList != null) {
+            final TintInfo tintInfo = new TintInfo();
+            tintInfo.mHasTintList = true;
+            tintInfo.mTintList = tintList;
+        }
+        return null;
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
new file mode 100644
index 0000000..18047e7
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+class AppCompatTextHelperV17 extends AppCompatTextHelper {
+
+    private static final int[] VIEW_ATTRS_v17 = {
+            android.R.attr.drawableStart, android.R.attr.drawableEnd };
+
+    private TintInfo mDrawableStartTint;
+    private TintInfo mDrawableEndTint;
+
+    AppCompatTextHelperV17(TextView view) {
+        super(view);
+    }
+
+    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+        super.loadFromAttributes(attrs, defStyleAttr);
+
+        final Context context = mView.getContext();
+        final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
+
+        TypedArray a = context.obtainStyledAttributes(attrs, VIEW_ATTRS_v17, defStyleAttr, 0);
+        if (a.hasValue(0)) {
+            mDrawableStartTint = createTintInfo(context, drawableManager, a.getResourceId(0, 0));
+        }
+        if (a.hasValue(1)) {
+            mDrawableEndTint = createTintInfo(context, drawableManager, a.getResourceId(1, 0));
+        }
+        a.recycle();
+    }
+
+    @Override
+    void applyCompoundDrawablesTints() {
+        super.applyCompoundDrawablesTints();
+
+        if (mDrawableStartTint != null || mDrawableEndTint != null) {
+            final Drawable[] compoundDrawables = mView.getCompoundDrawablesRelative();
+            applyCompoundDrawableTint(compoundDrawables[0], mDrawableStartTint);
+            applyCompoundDrawableTint(compoundDrawables[2], mDrawableEndTint);
+        }
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
index ccedfe0..b21f6bc 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
@@ -17,6 +17,12 @@
 package android.support.v7.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
 import android.support.v7.appcompat.R;
 import android.util.AttributeSet;
 import android.widget.TextView;
@@ -27,13 +33,19 @@
  * <ul>
  *     <li>Supports {@link R.attr#textAllCaps} style attribute which works back to
  *     {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li>
+ *     <li>Allows dynamic tint of it background via the background tint methods in
+ *     {@link android.support.v4.view.ViewCompat}.</li>
+ *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ *     {@link R.attr#backgroundTintMode}.</li>
  * </ul>
  *
  * <p>This will automatically be used when you use {@link TextView} in your layouts.
  * You should only need to manually use this class when writing custom views.</p>
  */
-public class AppCompatTextView extends TextView {
+public class AppCompatTextView extends TextView implements TintableBackgroundView {
 
+    private AppCompatDrawableManager mDrawableManager;
+    private AppCompatBackgroundHelper mBackgroundTintHelper;
     private AppCompatTextHelper mTextHelper;
 
     public AppCompatTextView(Context context) {
@@ -47,8 +59,81 @@
     public AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        mTextHelper = new AppCompatTextHelper(this);
+        mDrawableManager = AppCompatDrawableManager.get();
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
+        mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+        mTextHelper = AppCompatTextHelper.create(this);
         mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+        mTextHelper.applyCompoundDrawablesTints();
+    }
+
+    @Override
+    public void setBackgroundResource(@DrawableRes int resId) {
+        super.setBackgroundResource(resId);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundResource(resId);
+        }
+    }
+
+    @Override
+    public void setBackgroundDrawable(Drawable background) {
+        super.setBackgroundDrawable(background);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundDrawable(background);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public ColorStateList getSupportBackgroundTintList() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public PorterDuff.Mode getSupportBackgroundTintMode() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
     }
 
     @Override
@@ -58,4 +143,15 @@
             mTextHelper.onSetTextAppearance(context, resId);
         }
     }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.applySupportBackgroundTint();
+        }
+        if (mTextHelper != null) {
+            mTextHelper.applyCompoundDrawablesTints();
+        }
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java b/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
new file mode 100644
index 0000000..20fa89d
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ *
+ * @hide
+ */
+public class ButtonBarLayout extends LinearLayout {
+
+    /** Whether the current configuration allows stacking. */
+    private boolean mAllowStacking;
+    private int mLastWidthSize = -1;
+
+    public ButtonBarLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ButtonBarLayout);
+        mAllowStacking = ta.getBoolean(R.styleable.ButtonBarLayout_allowStacking, false);
+        ta.recycle();
+    }
+
+    public void setAllowStacking(boolean allowStacking) {
+        if (mAllowStacking != allowStacking) {
+            mAllowStacking = allowStacking;
+            if (!mAllowStacking && getOrientation() == LinearLayout.VERTICAL) {
+                setStacked(false);
+            }
+            requestLayout();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        if (mAllowStacking) {
+            if (widthSize > mLastWidthSize && isStacked()) {
+                // We're being measured wider this time, try un-stacking.
+                setStacked(false);
+            }
+            mLastWidthSize = widthSize;
+        }
+        boolean needsRemeasure = false;
+        // If we're not stacked, make sure the measure spec is AT_MOST rather
+        // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we
+        // know to stack the buttons.
+        final int initialWidthMeasureSpec;
+        if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+            initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
+            // We'll need to remeasure again to fill excess space.
+            needsRemeasure = true;
+        } else {
+            initialWidthMeasureSpec = widthMeasureSpec;
+        }
+        super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
+        if (mAllowStacking && !isStacked()) {
+            final int measuredWidth = getMeasuredWidthAndState();
+            final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+            if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+                setStacked(true);
+                // Measure again in the new orientation.
+                needsRemeasure = true;
+            }
+        }
+        if (needsRemeasure) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    private void setStacked(boolean stacked) {
+        setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+        setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+        final View spacer = findViewById(R.id.spacer);
+        if (spacer != null) {
+            spacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+        }
+        // Reverse the child order. This is specific to the Material button
+        // bar's layout XML and will probably not generalize.
+        final int childCount = getChildCount();
+        for (int i = childCount - 2; i >= 0; i--) {
+            bringChildToFront(getChildAt(i));
+        }
+    }
+
+    private boolean isStacked() {
+        return getOrientation() == LinearLayout.VERTICAL;
+    }
+}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ContentFrameLayout.java b/v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java
similarity index 89%
rename from v7/appcompat/src/android/support/v7/internal/widget/ContentFrameLayout.java
rename to v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java
index 7de9c8b..9a0de68 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ContentFrameLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.graphics.Rect;
@@ -33,6 +33,11 @@
  */
 public class ContentFrameLayout extends FrameLayout {
 
+    public interface OnAttachListener {
+        void onDetachedFromWindow();
+        void onAttachedFromWindow();
+    }
+
     private TypedValue mMinWidthMajor;
     private TypedValue mMinWidthMinor;
     private TypedValue mFixedWidthMajor;
@@ -42,6 +47,8 @@
 
     private final Rect mDecorPadding;
 
+    private OnAttachListener mAttachListener;
+
     public ContentFrameLayout(Context context) {
         this(context, null);
     }
@@ -62,6 +69,10 @@
         fitSystemWindows(insets);
     }
 
+    public void setAttachListener(OnAttachListener attachListener) {
+        mAttachListener = attachListener;
+    }
+
     /**
      * Notify this view of the window decor view's padding. We use these values when working out
      * our size for the window size attributes.
@@ -181,4 +192,20 @@
         if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
         return mFixedHeightMinor;
     }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (mAttachListener != null) {
+            mAttachListener.onAttachedFromWindow();
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mAttachListener != null) {
+            mAttachListener.onDetachedFromWindow();
+        }
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DecorContentParent.java b/v7/appcompat/src/android/support/v7/widget/DecorContentParent.java
similarity index 94%
rename from v7/appcompat/src/android/support/v7/internal/widget/DecorContentParent.java
rename to v7/appcompat/src/android/support/v7/widget/DecorContentParent.java
index e4400ac..a311416 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DecorContentParent.java
+++ b/v7/appcompat/src/android/support/v7/widget/DecorContentParent.java
@@ -15,11 +15,11 @@
  */
 
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
-import android.support.v7.internal.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuPresenter;
 import android.util.SparseArray;
 import android.view.Menu;
 import android.view.Window;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java b/v7/appcompat/src/android/support/v7/widget/DecorToolbar.java
similarity index 95%
rename from v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java
rename to v7/appcompat/src/android/support/v7/widget/DecorToolbar.java
index 52d53b3..a334139 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java
+++ b/v7/appcompat/src/android/support/v7/widget/DecorToolbar.java
@@ -15,14 +15,14 @@
  */
 
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
 import android.support.v4.view.ViewPropertyAnimatorCompat;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
 import android.util.SparseArray;
 import android.view.Menu;
 import android.view.View;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DialogTitle.java b/v7/appcompat/src/android/support/v7/widget/DialogTitle.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/DialogTitle.java
rename to v7/appcompat/src/android/support/v7/widget/DialogTitle.java
index 446d70d..052efff 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DialogTitle.java
+++ b/v7/appcompat/src/android/support/v7/widget/DialogTitle.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DrawableUtils.java b/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/DrawableUtils.java
rename to v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
index 1ff5e4d..b57b40f 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DrawableUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -25,10 +25,7 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
-/**
- * @hide
- */
-public class DrawableUtils {
+class DrawableUtils {
 
     private static final String TAG = "DrawableUtils";
 
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsFrameLayout.java b/v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsFrameLayout.java
rename to v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java
index 49f95fa..53750f8 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsFrameLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.graphics.Rect;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsLinearLayout.java b/v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsLinearLayout.java
rename to v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java
index 6adf74d..e2f7a73 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsLinearLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.graphics.Rect;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java b/v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java
similarity index 95%
rename from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
rename to v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java
index c84fda0..098a23e 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
+++ b/v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.graphics.Rect;
 
diff --git a/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java b/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
index b89115c..a6dce15 100644
--- a/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
@@ -25,8 +25,6 @@
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
diff --git a/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java b/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
index 0d2bcb8..5779599 100644
--- a/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
+++ b/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
@@ -26,12 +26,11 @@
 import android.os.SystemClock;
 import android.support.v4.text.TextUtilsCompat;
 import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewPropertyAnimatorCompat;
 import android.support.v4.widget.ListViewAutoScrollHelper;
 import android.support.v4.widget.PopupWindowCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.AppCompatPopupWindow;
-import android.support.v7.internal.widget.ListViewCompat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
@@ -43,6 +42,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.WindowManager;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.LinearLayout;
@@ -74,6 +74,7 @@
     private static final int EXPAND_LIST_TIMEOUT = 250;
 
     private static Method sClipToWindowEnabledMethod;
+    private static Method sGetMaxAvailableHeightMethod;
 
     static {
         try {
@@ -82,6 +83,13 @@
         } catch (NoSuchMethodException e) {
             Log.i(TAG, "Could not find method setClipToScreenEnabled() on PopupWindow. Oh well.");
         }
+        try {
+            sGetMaxAvailableHeightMethod = PopupWindow.class.getDeclaredMethod(
+                    "getMaxAvailableHeight", View.class, int.class, boolean.class);
+        } catch (NoSuchMethodException e) {
+            Log.i(TAG, "Could not find method getMaxAvailableHeight(View, int, boolean)"
+                    + " on PopupWindow. Oh well.");
+        }
     }
 
     private Context mContext;
@@ -93,6 +101,7 @@
     private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
     private int mDropDownHorizontalOffset;
     private int mDropDownVerticalOffset;
+    private int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
     private boolean mDropDownVerticalOffsetSet;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
@@ -119,7 +128,7 @@
     private final ListSelectorHider mHideSelector = new ListSelectorHider();
     private Runnable mShowDropDownRunnable;
 
-    private Handler mHandler = new Handler();
+    private final Handler mHandler;
 
     private Rect mTempRect = new Rect();
 
@@ -226,6 +235,7 @@
      */
     public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         mContext = context;
+        mHandler = new Handler(context.getMainLooper());
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ListPopupWindow,
                 defStyleAttr, defStyleRes);
@@ -531,6 +541,19 @@
     }
 
     /**
+     * Set the layout type for this popup window.
+     * <p>
+     * See {@link WindowManager.LayoutParams#type} for possible values.
+     *
+     * @param layoutType Layout type for this window.
+     *
+     * @see WindowManager.LayoutParams#type
+     */
+    public void setWindowLayoutType(int layoutType) {
+        mDropDownWindowLayoutType = layoutType;
+    }
+
+    /**
      * Sets a listener to receive events when a list item is clicked.
      *
      * @param clickListener Listener to register
@@ -583,12 +606,11 @@
     public void show() {
         int height = buildDropDown();
 
-        int widthSpec = 0;
-        int heightSpec = 0;
-
         boolean noInputMethod = isInputMethodNotNeeded();
+        PopupWindowCompat.setWindowLayoutType(mPopup, mDropDownWindowLayoutType);
 
         if (mPopup.isShowing()) {
+            final int widthSpec;
             if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
                 // The call to PopupWindow's update method below can accept -1 for any
                 // value you do not want to update.
@@ -599,19 +621,19 @@
                 widthSpec = mDropDownWidth;
             }
 
+            final int heightSpec;
             if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
                 // The call to PopupWindow's update method below can accept -1 for any
                 // value you do not want to update.
                 heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
                 if (noInputMethod) {
-                    mPopup.setWindowLayoutMode(
-                            mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
-                                    ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
+                    mPopup.setWidth(mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+                            ViewGroup.LayoutParams.MATCH_PARENT : 0);
+                    mPopup.setHeight(0);
                 } else {
-                    mPopup.setWindowLayoutMode(
-                            mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
-                                    ViewGroup.LayoutParams.MATCH_PARENT : 0,
-                            ViewGroup.LayoutParams.MATCH_PARENT);
+                    mPopup.setWidth(mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+                                    ViewGroup.LayoutParams.MATCH_PARENT : 0);
+                    mPopup.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
                 }
             } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
                 heightSpec = height;
@@ -622,29 +644,33 @@
             mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
 
             mPopup.update(getAnchorView(), mDropDownHorizontalOffset,
-                    mDropDownVerticalOffset, widthSpec, heightSpec);
+                            mDropDownVerticalOffset, (widthSpec < 0)? -1 : widthSpec,
+                            (heightSpec < 0)? -1 : heightSpec);
         } else {
+            final int widthSpec;
             if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
                 widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
             } else {
                 if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
-                    mPopup.setWidth(getAnchorView().getWidth());
+                    widthSpec = getAnchorView().getWidth();
                 } else {
-                    mPopup.setWidth(mDropDownWidth);
+                    widthSpec = mDropDownWidth;
                 }
             }
 
+            final int heightSpec;
             if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
                 heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
             } else {
                 if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
-                    mPopup.setHeight(height);
+                    heightSpec = height;
                 } else {
-                    mPopup.setHeight(mDropDownHeight);
+                    heightSpec = mDropDownHeight;
                 }
             }
 
-            mPopup.setWindowLayoutMode(widthSpec, heightSpec);
+            mPopup.setWidth(widthSpec);
+            mPopup.setHeight(heightSpec);
             setPopupClipToScreenEnabled(true);
 
             // use outside touchable to dismiss drop down when touching outside of it, so
@@ -1126,10 +1152,19 @@
                         break;
                 }
 
-                // measure the hint's height to find how much more vertical space
-                // we need to add to the drop down's height
-                int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
-                int heightSpec = MeasureSpec.UNSPECIFIED;
+                // Measure the hint's height to find how much more vertical
+                // space we need to add to the drop down's height.
+                final int widthSize;
+                final int widthMode;
+                if (mDropDownWidth >= 0) {
+                    widthMode = MeasureSpec.AT_MOST;
+                    widthSize = mDropDownWidth;
+                } else {
+                    widthMode = MeasureSpec.UNSPECIFIED;
+                    widthSize = 0;
+                }
+                final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+                final int heightSpec = MeasureSpec.UNSPECIFIED;
                 hintView.measure(widthSpec, heightSpec);
 
                 hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
@@ -1169,11 +1204,10 @@
         }
 
         // Max height available on the screen for a popup.
-        boolean ignoreBottomDecorations =
+        final boolean ignoreBottomDecorations =
                 mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
-        final int maxHeight = mPopup.getMaxAvailableHeight(
-                getAnchorView(), mDropDownVerticalOffset /*, ignoreBottomDecorations*/);
-
+        final int maxHeight = getMaxAvailableHeight(getAnchorView(), mDropDownVerticalOffset,
+                ignoreBottomDecorations);
         if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
             return maxHeight + padding;
         }
@@ -1629,6 +1663,11 @@
             // This will call through to updateSelectorState()
             drawableStateChanged();
 
+            final View motionView = getChildAt(mMotionPosition - getFirstVisiblePosition());
+            if (motionView != null) {
+                motionView.setPressed(false);
+            }
+
             if (mClickAnimation != null) {
                 mClickAnimation.cancel();
                 mClickAnimation = null;
@@ -1638,11 +1677,37 @@
         private void setPressedItem(View child, int position, float x, float y) {
             mDrawsInPressedState = true;
 
-            // Ordering is essential. First update the pressed state and layout
-            // the children. This will ensure the selector actually gets drawn.
-            setPressed(true);
+            // Ordering is essential. First, update the container's pressed state.
+            if (Build.VERSION.SDK_INT >= 21) {
+                drawableHotspotChanged(x, y);
+            }
+            if (!isPressed()) {
+                setPressed(true);
+            }
+
+            // Next, run layout to stabilize child positions.
             layoutChildren();
 
+            // Manage the pressed view based on motion position. This allows us to
+            // play nicely with actual touch and scroll events.
+            if (mMotionPosition != INVALID_POSITION) {
+                final View motionView = getChildAt(mMotionPosition - getFirstVisiblePosition());
+                if (motionView != null && motionView != child && motionView.isPressed()) {
+                    motionView.setPressed(false);
+                }
+            }
+            mMotionPosition = position;
+
+            // Offset for child coordinates.
+            final float childX = x - child.getLeft();
+            final float childY = y - child.getTop();
+            if (Build.VERSION.SDK_INT >= 21) {
+                child.drawableHotspotChanged(childX, childY);
+            }
+            if (!child.isPressed()) {
+                child.setPressed(true);
+            }
+
             // Ensure that keyboard focus starts from the last touched position.
             setSelection(position);
             positionSelectorLikeTouchCompat(position, child, x, y);
@@ -1697,7 +1762,6 @@
         public boolean hasFocus() {
             return mHijackFocus || super.hasFocus();
         }
-
     }
 
     private class PopupDataSetObserver extends DataSetObserver {
@@ -1723,8 +1787,9 @@
 
     private class ResizePopupRunnable implements Runnable {
         public void run() {
-            if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() &&
-                    mDropDownList.getChildCount() <= mListItemExpandMaximum) {
+            if (mDropDownList != null && ViewCompat.isAttachedToWindow(mDropDownList)
+                    && mDropDownList.getCount() > mDropDownList.getChildCount()
+                    && mDropDownList.getChildCount() <= mListItemExpandMaximum) {
                 mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
                 show();
             }
@@ -1777,4 +1842,16 @@
         }
     }
 
+    private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
+        if (sGetMaxAvailableHeightMethod != null) {
+            try {
+                return (int) sGetMaxAvailableHeightMethod.invoke(mPopup, anchor, yOffset,
+                        ignoreBottomDecorations);
+            } catch (Exception e) {
+                Log.i(TAG, "Could not call getMaxAvailableHeightMethod(View, int, boolean)"
+                        + " on PopupWindow. Using the public version.");
+            }
+        }
+        return mPopup.getMaxAvailableHeight(anchor, yOffset);
+    }
 }
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ListViewCompat.java b/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
similarity index 94%
rename from v7/appcompat/src/android/support/v7/internal/widget/ListViewCompat.java
rename to v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
index e2e6c4c..573a1f3 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ListViewCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -23,6 +23,7 @@
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v7.graphics.drawable.DrawableWrapper;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AbsListView;
@@ -50,6 +51,8 @@
     int mSelectionRightPadding = 0;
     int mSelectionBottomPadding = 0;
 
+    protected int mMotionPosition;
+
     private Field mIsChildViewEnabled;
 
     private GateKeeperDrawable mSelector;
@@ -107,6 +110,16 @@
         super.dispatchDraw(canvas);
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mMotionPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
+                break;
+        }
+        return super.onTouchEvent(ev);
+    }
+
     protected void updateSelectorStateCompat() {
         Drawable selector = getSelector();
         if (selector != null && shouldShowSelectorCompat()) {
@@ -291,8 +304,14 @@
 
             // Compute child height spec
             int heightMeasureSpec;
-            final ViewGroup.LayoutParams childLp = child.getLayoutParams();
-            if (childLp != null && childLp.height > 0) {
+            ViewGroup.LayoutParams childLp = child.getLayoutParams();
+
+            if (childLp == null) {
+                childLp = generateDefaultLayoutParams();
+                child.setLayoutParams(childLp);
+            }
+
+            if (childLp.height > 0) {
                 heightMeasureSpec = MeasureSpec.makeMeasureSpec(childLp.height,
                         MeasureSpec.EXACTLY);
             } else {
@@ -300,6 +319,10 @@
             }
             child.measure(widthMeasureSpec, heightMeasureSpec);
 
+            // Since this view was measured directly aginst the parent measure
+            // spec, we must measure it again before reuse.
+            child.forceLayout();
+
             if (i > 0) {
                 // Count the divider for all but one child
                 returnedHeight += dividerHeight;
@@ -383,6 +406,4 @@
             return false;
         }
     }
-
-
 }
diff --git a/v7/appcompat/src/android/support/v7/widget/PopupMenu.java b/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
index 5c4dde8..7f097c7 100644
--- a/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
+++ b/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
@@ -20,11 +20,11 @@
 import android.content.Context;
 import android.support.annotation.MenuRes;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.view.menu.SubMenuBuilder;
 import android.view.Gravity;
 import android.view.Menu;
 import android.view.MenuInflater;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ResourcesWrapper.java b/v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/ResourcesWrapper.java
rename to v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java
index 48ebab8..828a792 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ResourcesWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -27,11 +26,9 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.Movie;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Drawable.ConstantState;
 import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.LongSparseArray;
 import android.util.TypedValue;
 
 import java.io.IOException;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/RtlSpacingHelper.java b/v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/widget/RtlSpacingHelper.java
rename to v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java
index e6c80d1..6a4e360 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/RtlSpacingHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java
@@ -15,16 +15,14 @@
  */
 
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 /**
  * RtlSpacingHelper manages the relationship between left/right and start/end for views
  * that need to maintain both absolute and relative settings for a form of spacing similar
  * to view padding.
- *
- * @hide
  */
-public class RtlSpacingHelper {
+class RtlSpacingHelper {
     public static final int UNDEFINED = Integer.MIN_VALUE;
 
     private int mLeft = 0;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java
rename to v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
index 0d27d32..06118bf 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -25,10 +25,7 @@
 import android.support.v4.view.ViewPropertyAnimatorListener;
 import android.support.v7.app.ActionBar;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ActionBarPolicy;
-import android.support.v7.widget.AppCompatSpinner;
-import android.support.v7.widget.AppCompatTextView;
-import android.support.v7.widget.LinearLayoutCompat;
+import android.support.v7.view.ActionBarPolicy;
 import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
 import android.view.Gravity;
diff --git a/v7/appcompat/src/android/support/v7/widget/SearchView.java b/v7/appcompat/src/android/support/v7/widget/SearchView.java
index 553e3ab..e4644d0 100644
--- a/v7/appcompat/src/android/support/v7/widget/SearchView.java
+++ b/v7/appcompat/src/android/support/v7/widget/SearchView.java
@@ -39,9 +39,6 @@
 import android.support.v4.view.KeyEventCompat;
 import android.support.v4.widget.CursorAdapter;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
 import android.support.v7.view.CollapsibleActionView;
 import android.text.Editable;
 import android.text.InputType;
@@ -162,7 +159,7 @@
     private SearchableInfo mSearchable;
     private Bundle mAppSearchData;
 
-    private final TintManager mTintManager;
+    private final AppCompatDrawableManager mDrawableManager;
 
     static final AutoCompleteTextViewReflector HIDDEN_METHOD_INVOKER = new AutoCompleteTextViewReflector();
 
@@ -278,10 +275,10 @@
     public SearchView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        mDrawableManager = AppCompatDrawableManager.get();
+
         final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context,
                 attrs, R.styleable.SearchView, defStyleAttr, 0);
-        // Keep the TintManager in case we need it later
-        mTintManager = a.getTintManager();
 
         final LayoutInflater inflater = LayoutInflater.from(context);
         final int layoutResId = a.getResourceId(
@@ -829,7 +826,15 @@
         mSearchButton.setVisibility(visCollapsed);
         updateSubmitButton(hasText);
         mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
-        mCollapsedIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
+
+        final int iconVisibility;
+        if (mCollapsedIcon.getDrawable() == null || mIconifiedByDefault) {
+            iconVisibility = GONE;
+        } else {
+            iconVisibility = VISIBLE;
+        }
+        mCollapsedIcon.setVisibility(iconVisibility);
+
         updateCloseButton();
         updateVoiceButton(!hasText);
         updateSubmitArea();
diff --git a/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java b/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java
index a840f95..25f6cc5 100644
--- a/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java
+++ b/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java
@@ -24,63 +24,101 @@
 import android.os.Build;
 import android.support.v4.view.ActionProvider;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.ActivityChooserModel;
-import android.support.v7.internal.widget.ActivityChooserView;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.widget.ActivityChooserModel.OnChooseActivityListener;
 import android.util.TypedValue;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.SubMenu;
 import android.view.View;
-import android.support.v7.internal.widget.ActivityChooserModel.OnChooseActivityListener;
 
 /**
- * This is a provider for a share action. It is responsible for creating views
- * that enable data sharing and also to show a sub menu with sharing activities
- * if the hosting item is placed on the overflow menu.
+ * Provides a share action, which is suitable for an activity's app bar. Creates
+ * views that enable data sharing. If the provider appears in the
+ * overflow menu, it creates a submenu with the appropriate sharing
+ * actions.
  *
- * <p class="note"><strong>Note:</strong> This class is included in the <a
- * href="{@docRoot}tools/extras/support-library.html">support library</a> for compatibility
- * with API level 7 and higher. If you're developing your app for API level 14 and higher
- * <em>only</em>, you should instead use the framework {@link android.widget.ShareActionProvider}
- * class.</p>
+ * <h3 id="add-share-action">Adding a share action</h3>
  *
- * <p>
- * Here is how to use the action provider with custom backing file in a {@link MenuItem}:
- * </p>
- * <pre><code>
- *  // In {@link android.app.Activity#onCreateOptionsMenu Activity.onCreateOptionsMenu()}
- *  public boolean onCreateOptionsMenu(Menu menu) {
- *      // Get the menu item.
- *      MenuItem menuItem = menu.findItem(R.id.my_menu_item);
- *      // Get the provider and hold onto it to set/change the share intent.
- *      mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);
- *      // Set history different from the default before getting the action
- *      // view since a call to {@link android.support.v4.view.MenuItemCompat#getActionView(android.view.MenuItem) MenuItemCompat.getActionView()} calls
- *      // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
- *      // line if using the default share history file is desired.
- *      mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
- *      . . .
- *  }
+ * <p>To add a "share" action to your activity, put a
+ * <code>ShareActionProvider</code> in the app bar's menu resource. For
+ * example:</p>
  *
- *  // Somewhere in the application.
- *  public void doShare(Intent shareIntent) {
- *      // When you want to share set the share intent.
- *      mShareActionProvider.setShareIntent(shareIntent);
- *  }
- * </code></pre>
- * <p>
- * <strong>Note:</strong> While the sample snippet demonstrates how to use this provider
- * in the context of a menu item, the use of the provider is not limited to menu items.
- * </p>
+ * <pre>
+ * &lt;item android:id="&#64;+id/action_share"
+ *      android:title="&#64;string/share"
+ *      app:showAsAction="ifRoom"
+ *      app:actionProviderClass="android.support.v7.widget.ShareActionProvider"/&gt;
+ * </pre>
  *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
+ * <p>You do not need to specify an icon, since the
+ * <code>ShareActionProvider</code> widget takes care of its own appearance and
+ * behavior. However, you do need to specify a title with
+ * <code>android:title</code>, in case the action ends up in the overflow
+ * menu.</p>
  *
- * <p>For information about how to use {@link ShareActionProvider}, see the
- * <a href="{@docRoot}guide/topics/ui/actionbar.html#ActionProvider">Action Bar</a> API guide.</p>
- * </div>
+ * <p>Next, set up the intent that contains the content your activity is
+ * able to share. You should create this intent in your handler for
+ * {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()},
+ * and update it every time the shareable content changes. To set up the
+ * intent:</p>
+ *
+ * <ol>
+ * <li>Get a reference to the ShareActionProvider by calling {@link
+ * android.view.MenuItem#getActionProvider getActionProvider()} and
+ * passing the share action's {@link android.view.MenuItem}. For
+ * example:
+ *
+ * <pre>
+ * MenuItem shareItem = menu.findItem(R.id.action_share);
+ * ShareActionProvider myShareActionProvider =
+ *     (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);</pre></li>
+ *
+ * <li>Create an intent with the {@link android.content.Intent#ACTION_SEND}
+ * action, and attach the content shared by the activity. For example, the
+ * following intent shares an image:
+ *
+ * <pre>
+ * Intent myShareIntent = new Intent(Intent.ACTION_SEND);
+ * myShareIntent.setType("image/*");
+ * myShareIntent.putExtra(Intent.EXTRA_STREAM, myImageUri);</pre></li>
+ *
+ * <li>Call {@link #setShareIntent setShareIntent()} to attach this intent to
+ * the action provider:
+ *
+ * <pre>
+ * myShareActionProvider.setShareIntent(myShareIntent);
+ * </pre></li>
+ *
+ * <li>When the content changes, modify the intent or create a new one,
+ * and call {@link #setShareIntent setShareIntent()} again. For example:
+ *
+ * <pre>
+ * // Image has changed! Update the intent:
+ * myShareIntent.putExtra(Intent.EXTRA_STREAM, myNewImageUri);
+ * myShareActionProvider.setShareIntent(myShareIntent);</pre></li>
+ * </ol>
+ *
+ * <h3 id="rankings">Share target rankings</h3>
+ *
+ * <p>The share action provider retains a ranking for each share target,
+ * based on how often the user chooses each one. The more often a user
+ * chooses a target, the higher its rank; the
+ * most-commonly used target appears in the app bar as the default target.</p>
+ *
+ * <p>By default, the target ranking information is stored in a private
+ * file with the name specified by {@link
+ * #DEFAULT_SHARE_HISTORY_FILE_NAME}. Ordinarily, the share action provider stores
+ * all the history in this single file. However, using a single set of
+ * rankings may not make sense if the
+ * share action provider is used for different kinds of content. For
+ * example, if the activity sometimes shares images and sometimes shares
+ * contacts, you would want to maintain two different sets of rankings.</p>
+ *
+ * <p>To set the history file, call {@link #setShareHistoryFileName
+ * setShareHistoryFileName()} and pass the name of an XML file. The file
+ * you specify is used until the next time you call {@link
+ * #setShareHistoryFileName setShareHistoryFileName()}.</p>
  *
  * @see ActionProvider
  */
@@ -188,7 +226,8 @@
         // Lookup and set the expand action icon.
         TypedValue outTypedValue = new TypedValue();
         mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
-        Drawable drawable = TintManager.getDrawable(mContext, outTypedValue.resourceId);
+        Drawable drawable = AppCompatDrawableManager.get()
+                .getDrawable(mContext, outTypedValue.resourceId);
         activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
         activityChooserView.setProvider(this);
 
diff --git a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
index 6aa55d7..f87109b 100644
--- a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
@@ -32,11 +32,7 @@
 import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.text.AllCapsTransformationMethod;
-import android.support.v7.internal.widget.DrawableUtils;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
+import android.support.v7.text.AllCapsTransformationMethod;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
@@ -145,7 +141,7 @@
     @SuppressWarnings("hiding")
     private final Rect mTempRect = new Rect();
 
-    private final TintManager mTintManager;
+    private final AppCompatDrawableManager mDrawableManager;
 
     private static final int[] CHECKED_STATE_SET = {
             android.R.attr.state_checked
@@ -216,7 +212,7 @@
             setSwitchTextAppearance(context, appearance);
         }
 
-        mTintManager = a.getTintManager();
+        mDrawableManager = AppCompatDrawableManager.get();
 
         a.recycle();
 
@@ -408,7 +404,7 @@
      * @param resId Resource ID of a track drawable
      */
     public void setTrackResource(int resId) {
-        setTrackDrawable(mTintManager.getDrawable(resId));
+        setTrackDrawable(mDrawableManager.getDrawable(getContext(), resId));
     }
 
     /**
@@ -438,7 +434,7 @@
      * @param resId Resource ID of a thumb drawable
      */
     public void setThumbResource(int resId) {
-        setThumbDrawable(mTintManager.getDrawable(resId));
+        setThumbDrawable(mDrawableManager.getDrawable(getContext(), resId));
     }
 
     /**
@@ -742,14 +738,36 @@
 
         if (newState != oldState) {
             playSoundEffect(SoundEffectConstants.CLICK);
-            setChecked(newState);
         }
+        // Always call setChecked so that the thumb is moved back to the correct edge
+        setChecked(newState);
         cancelSuperTouch(ev);
     }
 
-    private void animateThumbToCheckedState(boolean newCheckedState) {
-        mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1 : 0);
+    private void animateThumbToCheckedState(final boolean newCheckedState) {
+        if (mPositionAnimator != null) {
+            // If there's a current animator running, cancel it
+            cancelPositionAnimator();
+        }
+
+        mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1f : 0f);
         mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
+        mPositionAnimator.setAnimationListener(new Animation.AnimationListener() {
+            @Override
+            public void onAnimationStart(Animation animation) {}
+
+            @Override
+            public void onAnimationEnd(Animation animation) {
+                if (mPositionAnimator == animation) {
+                    // If we're still the active animation, ensure the final position
+                    setThumbPosition(newCheckedState ? 1f : 0f);
+                    mPositionAnimator = null;
+                }
+            }
+
+            @Override
+            public void onAnimationRepeat(Animation animation) {}
+        });
         startAnimation(mPositionAnimator);
     }
 
@@ -787,7 +805,7 @@
         // recursively with a different value, so load the REAL value...
         checked = isChecked();
 
-        if (getWindowToken() != null && ViewCompat.isLaidOut(this)) {
+        if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) {
             animateThumbToCheckedState(checked);
         } else {
             // Immediately move the thumb to the new position.
@@ -881,7 +899,7 @@
             int trackTop = switchTop;
             int trackRight = switchRight;
             int trackBottom = switchBottom;
-            if (thumbInsets != null && !thumbInsets.isEmpty()) {
+            if (thumbInsets != null) {
                 if (thumbInsets.left > padding.left) {
                     trackLeft += thumbInsets.left - padding.left;
                 }
@@ -1100,12 +1118,7 @@
                 mTrackDrawable.jumpToCurrentState();
             }
 
-            if (mPositionAnimator != null && !mPositionAnimator.hasEnded()) {
-                clearAnimation();
-                // Manually set our thumb position to the end state
-                setThumbPosition(mPositionAnimator.mEndPosition);
-                mPositionAnimator = null;
-            }
+            cancelPositionAnimator();
         }
     }
 
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ThemeUtils.java b/v7/appcompat/src/android/support/v7/widget/ThemeUtils.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/ThemeUtils.java
rename to v7/appcompat/src/android/support/v7/widget/ThemeUtils.java
index ed5b093..1c0151b 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ThemeUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/ThemeUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -23,10 +23,7 @@
 import android.support.v4.graphics.ColorUtils;
 import android.util.TypedValue;
 
-/**
- * @hide
- */
-public class ThemeUtils {
+class ThemeUtils {
 
     private static final ThreadLocal<TypedValue> TL_TYPED_VALUE = new ThreadLocal<>();
 
diff --git a/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java b/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
index 8bcc5e1..6016b57 100644
--- a/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
@@ -22,7 +22,7 @@
 import android.content.res.Resources.Theme;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.v7.internal.view.ContextThemeWrapper;
+import android.support.v7.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintContextWrapper.java b/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
similarity index 80%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintContextWrapper.java
rename to v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
index 3fdd971..ef12e06 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintContextWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -24,10 +24,8 @@
 /**
  * A {@link android.content.ContextWrapper} which returns a tint-aware
  * {@link android.content.res.Resources} instance from {@link #getResources()}.
- *
- * @hide
  */
-public class TintContextWrapper extends ContextWrapper {
+class TintContextWrapper extends ContextWrapper {
 
     public static Context wrap(Context context) {
         if (!(context instanceof TintContextWrapper)) {
@@ -45,7 +43,7 @@
     @Override
     public Resources getResources() {
         if (mResources == null) {
-            mResources = new TintResources(super.getResources(), TintManager.get(this));
+            mResources = new TintResources(super.getResources());
         }
         return mResources;
     }
@@ -53,13 +51,9 @@
     /**
      * This class allows us to intercept calls so that we can tint resources (if applicable).
      */
-    static class TintResources extends ResourcesWrapper {
-
-        private final TintManager mTintManager;
-
-        public TintResources(Resources resources, TintManager tintManager) {
+    class TintResources extends ResourcesWrapper {
+        public TintResources(Resources resources) {
             super(resources);
-            mTintManager = tintManager;
         }
 
         /**
@@ -71,7 +65,8 @@
         public Drawable getDrawable(int id) throws NotFoundException {
             Drawable d = super.getDrawable(id);
             if (d != null) {
-                mTintManager.tintDrawableUsingColorFilter(id, d);
+                AppCompatDrawableManager.get().tintDrawableUsingColorFilter(
+                        TintContextWrapper.this, id, d);
             }
             return d;
         }
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v7/appcompat/src/android/support/v7/widget/TintInfo.java
similarity index 90%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
rename to v7/appcompat/src/android/support/v7/widget/TintInfo.java
index 8eea38d..547220c 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v7/appcompat/src/android/support/v7/widget/TintInfo.java
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
 
-/**
- * @hide
- */
-public class TintInfo {
+class TintInfo {
     public ColorStateList mTintList;
     public PorterDuff.Mode mTintMode;
     public boolean mHasTintMode;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintTypedArray.java b/v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
similarity index 92%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintTypedArray.java
rename to v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
index 09e2b56..50e1046 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintTypedArray.java
+++ b/v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -36,8 +36,6 @@
     private final Context mContext;
     private final TypedArray mWrapped;
 
-    private TintManager mTintManager;
-
     public static TintTypedArray obtainStyledAttributes(Context context, AttributeSet set,
             int[] attrs) {
         TypedArray array = context.obtainStyledAttributes(set, attrs);
@@ -59,7 +57,7 @@
         if (mWrapped.hasValue(index)) {
             final int resourceId = mWrapped.getResourceId(index, 0);
             if (resourceId != 0) {
-                return getTintManager().getDrawable(resourceId);
+                return AppCompatDrawableManager.get().getDrawable(mContext, resourceId);
             }
         }
         return mWrapped.getDrawable(index);
@@ -69,7 +67,7 @@
         if (mWrapped.hasValue(index)) {
             final int resourceId = mWrapped.getResourceId(index, 0);
             if (resourceId != 0) {
-                return getTintManager().getDrawable(resourceId, true);
+                return AppCompatDrawableManager.get().getDrawable(mContext, resourceId, true);
             }
         }
         return null;
@@ -187,11 +185,4 @@
         return mWrapped.getChangingConfigurations();
     }
 
-    public TintManager getTintManager() {
-        if (mTintManager == null) {
-            mTintManager = TintManager.get(mContext);
-        }
-        return mTintManager;
-    }
-
 }
diff --git a/v7/appcompat/src/android/support/v7/widget/Toolbar.java b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
index 0e8e318..ca4d199 100644
--- a/v7/appcompat/src/android/support/v7/widget/Toolbar.java
+++ b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
@@ -17,9 +17,6 @@
 package android.support.v7.widget;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Parcel;
@@ -38,21 +35,13 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v7.app.ActionBar;
 import android.support.v7.appcompat.R;
-import android.support.v7.graphics.drawable.DrawableUtils;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.DecorToolbar;
-import android.support.v7.internal.widget.RtlSpacingHelper;
-import android.support.v7.internal.widget.TintInfo;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ToolbarWidgetWrapper;
-import android.support.v7.internal.widget.ViewUtils;
 import android.support.v7.view.CollapsibleActionView;
+import android.support.v7.view.SupportMenuInflater;
+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.text.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -197,7 +186,7 @@
         }
     };
 
-    private final TintManager mTintManager;
+    private final AppCompatDrawableManager mDrawableManager;
 
     public Toolbar(Context context) {
         this(context, null);
@@ -306,8 +295,7 @@
         }
         a.recycle();
 
-        // Keep the TintManager in case we need it later
-        mTintManager = a.getTintManager();
+        mDrawableManager = AppCompatDrawableManager.get();
     }
 
     /**
@@ -354,7 +342,7 @@
      * @param resId ID of a drawable resource
      */
     public void setLogo(@DrawableRes int resId) {
-        setLogo(mTintManager.getDrawable(resId));
+        setLogo(mDrawableManager.getDrawable(getContext(), resId));
     }
 
     /** @hide */
@@ -781,7 +769,7 @@
      * @param resId Resource ID of a drawable to set
      */
     public void setNavigationIcon(@DrawableRes int resId) {
-        setNavigationIcon(mTintManager.getDrawable(resId));
+        setNavigationIcon(mDrawableManager.getDrawable(getContext(), resId));
     }
 
     /**
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
similarity index 90%
rename from v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java
rename to v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
index 50e03c9..0576c153 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
@@ -15,7 +15,7 @@
  */
 
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.app.ActionBar;
 import android.content.Context;
@@ -24,13 +24,11 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewPropertyAnimatorCompat;
 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
+import android.support.v7.app.WindowDecorActionBar;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.menu.ActionMenuItem;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.widget.ActionMenuPresenter;
-import android.support.v7.widget.AppCompatSpinner;
-import android.support.v7.widget.Toolbar;
+import android.support.v7.view.menu.ActionMenuItem;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -50,7 +48,7 @@
  *
  * <p>ToolbarWidgetWrapper manages the differences between Toolbar and ActionBarView
  * so that either variant acting as a
- * {@link android.support.v7.internal.app.WindowDecorActionBar WindowDecorActionBar} can behave
+ * {@link WindowDecorActionBar WindowDecorActionBar} can behave
  * in the same way.</p>
  *
  * @hide
@@ -85,7 +83,7 @@
 
     private int mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
 
-    private final TintManager mTintManager;
+    private final AppCompatDrawableManager mDrawableManager;
     private int mDefaultNavigationContentDescription = 0;
     private Drawable mDefaultNavigationIcon;
 
@@ -174,18 +172,16 @@
             }
 
             a.recycle();
-            // Keep the TintManager in case we need it later
-            mTintManager = a.getTintManager();
         } else {
             mDisplayOpts = detectDisplayOptions();
-            // Create a TintManager in case we need it later
-            mTintManager = TintManager.get(toolbar.getContext());
         }
 
+        mDrawableManager = AppCompatDrawableManager.get();
+
         setDefaultNavigationContentDescription(defaultNavigationContentDescription);
         mHomeDescription = mToolbar.getNavigationContentDescription();
 
-        setDefaultNavigationIcon(mTintManager.getDrawable(defaultNavigationIcon));
+        setDefaultNavigationIcon(mDrawableManager.getDrawable(getContext(), defaultNavigationIcon));
 
         mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
             final ActionMenuItem mNavItem = new ActionMenuItem(mToolbar.getContext(),
@@ -322,7 +318,7 @@
 
     @Override
     public void setIcon(int resId) {
-        setIcon(resId != 0 ? mTintManager.getDrawable(resId) : null);
+        setIcon(resId != 0 ? mDrawableManager.getDrawable(getContext(), resId) : null);
     }
 
     @Override
@@ -333,7 +329,7 @@
 
     @Override
     public void setLogo(int resId) {
-        setLogo(resId != 0 ? mTintManager.getDrawable(resId) : null);
+        setLogo(resId != 0 ? mDrawableManager.getDrawable(getContext(), resId) : null);
     }
 
     @Override
@@ -587,37 +583,31 @@
     }
 
     @Override
-    public ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration) {
-        if (visibility == View.GONE) {
-            ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(0f);
-            anim.setDuration(duration);
-            anim.setListener(new ViewPropertyAnimatorListenerAdapter() {
-                private boolean mCanceled = false;
-                @Override
-                public void onAnimationEnd(View view) {
-                    if (!mCanceled) {
-                        mToolbar.setVisibility(View.GONE);
-                    }
-                }
+    public ViewPropertyAnimatorCompat setupAnimatorToVisibility(final int visibility,
+            final long duration) {
+        return ViewCompat.animate(mToolbar)
+                .alpha(visibility == View.VISIBLE ? 1f : 0f)
+                .setDuration(duration)
+                .setListener(new ViewPropertyAnimatorListenerAdapter() {
+                    private boolean mCanceled = false;
 
-                @Override
-                public void onAnimationCancel(View view) {
-                    mCanceled = true;
-                }
-            });
-            return anim;
-        } else if (visibility == View.VISIBLE) {
-            ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(1f);
-            anim.setDuration(duration);
-            anim.setListener(new ViewPropertyAnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(View view) {
-                    mToolbar.setVisibility(View.VISIBLE);
-                }
-            });
-            return anim;
-        }
-        return null;
+                    @Override
+                    public void onAnimationStart(View view) {
+                        mToolbar.setVisibility(View.VISIBLE);
+                    }
+
+                    @Override
+                    public void onAnimationEnd(View view) {
+                        if (!mCanceled) {
+                            mToolbar.setVisibility(visibility);
+                        }
+                    }
+
+                    @Override
+                    public void onAnimationCancel(View view) {
+                        mCanceled = true;
+                    }
+                });
     }
 
     @Override
@@ -629,8 +619,7 @@
     @Override
     public void setNavigationIcon(int resId) {
         setNavigationIcon(resId != 0
-                ? mTintManager.getDrawable(resId)
-                : null);
+                ? AppCompatDrawableManager.get().getDrawable(getContext(), resId) : null);
     }
 
     @Override
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ViewStubCompat.java b/v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/widget/ViewStubCompat.java
rename to v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java
index 10873a7..11cd213 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ViewStubCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -26,7 +26,6 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 
-
 import java.lang.ref.WeakReference;
 
 /**
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ViewUtils.java b/v7/appcompat/src/android/support/v7/widget/ViewUtils.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ViewUtils.java
rename to v7/appcompat/src/android/support/v7/widget/ViewUtils.java
index a56cf3f..0ae4951 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ViewUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/ViewUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
 
 import android.graphics.Rect;
 import android.os.Build;
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
index 8adc940..44f9207 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
@@ -106,10 +106,30 @@
         getInstrumentation().waitForIdleSync();
         assertTrue("onMenuOpened called", getActivity().wasOnMenuOpenedCalled());
 
-        // TODO Re-enable this in v23
-        //getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
-        //getInstrumentation().waitForIdleSync();
-        //assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+        getInstrumentation().waitForIdleSync();
+        assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
+    }
+
+    @Test
+    public void testBackPressWithMenuInvokesOnPanelClosed() throws InterruptedException {
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+        getInstrumentation().waitForIdleSync();
+
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        getInstrumentation().waitForIdleSync();
+        assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
+    }
+
+    @Test
+    public void testBackPressWithEmptyMenuDestroysActivity() throws InterruptedException {
+        repopulateWithEmptyMenu();
+
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+        getInstrumentation().waitForIdleSync();
+
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        waitAssertDestroyed();
     }
 
     @Test
@@ -141,4 +161,28 @@
         assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_MENU, upEvent.getKeyCode());
     }
 
+    private void waitAssertDestroyed() throws InterruptedException {
+        int count = 0;
+        while (count++ < 10) {
+            if (!getActivity().isDestroyed()) {
+                Thread.sleep(50);
+            } else {
+                break;
+            }
+        }
+        assertTrue("Activity destroyed", getActivity().isDestroyed());
+    }
+
+    private void repopulateWithEmptyMenu() throws InterruptedException {
+        int count = 0;
+        getActivity().setShouldPopulateOptionsMenu(false);
+        while (count++ < 10) {
+            Menu menu = getActivity().getMenu();
+            if (menu == null || menu.size() != 0) {
+                Thread.sleep(50);
+            } else {
+                return;
+            }
+        }
+    }
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java b/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java
index f336e91..ebbd0d5 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java
@@ -37,6 +37,11 @@
     private boolean mOnMenuOpenedCalled;
     private boolean mOnPanelClosedCalled;
 
+    private boolean mShouldPopulateOptionsMenu = true;
+
+    private boolean mOnBackPressedCalled;
+    private boolean mDestroyed;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -113,8 +118,13 @@
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         mMenu = menu;
-        getMenuInflater().inflate(R.menu.sample_actions, menu);
-        return true;
+        if (mShouldPopulateOptionsMenu) {
+            getMenuInflater().inflate(R.menu.sample_actions, menu);
+            return true;
+        } else {
+            menu.clear();
+            return super.onCreateOptionsMenu(menu);
+        }
     }
 
     public boolean expandSearchView() {
@@ -140,4 +150,36 @@
         mOnMenuOpenedCalled = false;
         mOnPanelClosedCalled = false;
     }
+
+    public void setShouldPopulateOptionsMenu(boolean populate) {
+        mShouldPopulateOptionsMenu = populate;
+        if (mMenu != null) {
+            supportInvalidateOptionsMenu();
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mDestroyed = true;
+    }
+
+    @Override
+    public void onBackPressed() {
+        super.onBackPressed();
+        mOnBackPressedCalled = true;
+    }
+
+    public boolean wasOnBackPressedCalled() {
+        return mOnBackPressedCalled;
+    }
+
+    public Menu getMenu() {
+        return mMenu;
+    }
+
+    @Override
+    public boolean isDestroyed() {
+        return mDestroyed;
+    }
 }
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 e9ede89..053e971 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
@@ -20,7 +20,6 @@
 
 import android.app.Dialog;
 import android.os.Bundle;
-import android.support.v7.internal.app.WindowDecorActionBar;
 
 public class DialogTestCase extends BaseInstrumentationTestCase<WindowDecorActionBarActivity> {
 
diff --git a/v7/cardview/Android.mk b/v7/cardview/Android.mk
index 91d82b4..dcbc4c6 100644
--- a/v7/cardview/Android.mk
+++ b/v7/cardview/Android.mk
@@ -26,6 +26,8 @@
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files := $(LOCAL_SRC_FILES)
+
 # A helper sub-library to resolve cyclic dependencies between CardView and platform dependent
 # implementations
 include $(CLEAR_VARS)
@@ -34,6 +36,8 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, base)
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of Eclair MR1 APIs
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-cardview-eclair-mr1
@@ -43,6 +47,8 @@
 LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of JB MR1 APIs
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-cardview-jellybean-mr1
@@ -52,6 +58,8 @@
 LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of L APIs
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-cardview-api21
@@ -62,6 +70,8 @@
 LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # Here is the final static library that apps can link against.
 # The R class is automatically excluded from the generated library.
 # Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -74,11 +84,12 @@
 LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # API Check
 # ---------------------------------------------
 support_module := $(LOCAL_MODULE)
 support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
-support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES) android-support-v7-cardview
+support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
 support_module_java_packages := android.support.v7.widget
 include $(SUPPORT_API_CHECK)
diff --git a/v7/cardview/api/23.txt b/v7/cardview/api/23.0.0.txt
similarity index 100%
rename from v7/cardview/api/23.txt
rename to v7/cardview/api/23.0.0.txt
diff --git a/v7/cardview/api/23.txt b/v7/cardview/api/23.1.0.txt
similarity index 100%
copy from v7/cardview/api/23.txt
copy to v7/cardview/api/23.1.0.txt
diff --git a/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java b/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
index 3477761..5dba5d6 100644
--- a/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
+++ b/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
@@ -15,11 +15,15 @@
  */
 package android.support.v7.widget;
 
+import android.content.res.ColorStateList;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -29,7 +33,7 @@
 
 /**
  * Very simple drawable that draws a rounded rectangle background with arbitrary corners and also
- * reports proper outline for L.
+ * reports proper outline for Lollipop.
  * <p>
  * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable.
  */
@@ -42,6 +46,10 @@
     private boolean mInsetForPadding = false;
     private boolean mInsetForRadius = true;
 
+    private PorterDuffColorFilter mTintFilter;
+    private ColorStateList mTint;
+    private PorterDuff.Mode mTintMode;
+
     public RoundRectDrawable(int backgroundColor, float radius) {
         mRadius = radius;
         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
@@ -68,7 +76,21 @@
 
     @Override
     public void draw(Canvas canvas) {
-        canvas.drawRoundRect(mBoundsF, mRadius, mRadius, mPaint);
+        final Paint paint = mPaint;
+
+        final boolean clearColorFilter;
+        if (mTintFilter != null && paint.getColorFilter() == null) {
+            paint.setColorFilter(mTintFilter);
+            clearColorFilter = true;
+        } else {
+            clearColorFilter = false;
+        }
+
+        canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint);
+
+        if (clearColorFilter) {
+            paint.setColorFilter(null);
+        }
     }
 
     private void updateBounds(Rect bounds) {
@@ -108,12 +130,12 @@
 
     @Override
     public void setAlpha(int alpha) {
-        // not supported because older versions do not support
+        mPaint.setAlpha(alpha);
     }
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        // not supported because older versions do not support
+        mPaint.setColorFilter(cf);
     }
 
     @Override
@@ -129,4 +151,44 @@
         mPaint.setColor(color);
         invalidateSelf();
     }
+
+    @Override
+    public void setTintList(ColorStateList tint) {
+        mTint = tint;
+        mTintFilter = createTintFilter(mTint, mTintMode);
+        invalidateSelf();
+    }
+
+    @Override
+    public void setTintMode(PorterDuff.Mode tintMode) {
+        mTintMode = tintMode;
+        mTintFilter = createTintFilter(mTint, mTintMode);
+        invalidateSelf();
+    }
+
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        if (mTint != null && mTintMode != null) {
+            mTintFilter = createTintFilter(mTint, mTintMode);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isStateful() {
+        return (mTint != null && mTint.isStateful()) || super.isStateful();
+    }
+
+    /**
+     * Ensures the tint filter is consistent with the current tint color and
+     * mode.
+     */
+    private PorterDuffColorFilter createTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) {
+        if (tint == null || tintMode == null) {
+            return null;
+        }
+        final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
+        return new PorterDuffColorFilter(color, tintMode);
+    }
 }
diff --git a/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java b/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java
index 054ada8..505edcc 100644
--- a/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java
+++ b/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java
@@ -131,8 +131,13 @@
     }
 
     void setShadowSize(float shadowSize, float maxShadowSize) {
-        if (shadowSize < 0 || maxShadowSize < 0) {
-            throw new IllegalArgumentException("invalid shadow size");
+        if (shadowSize < 0f) {
+            throw new IllegalArgumentException("Invalid shadow size " + shadowSize +
+                    ". Must be >= 0");
+        }
+        if (maxShadowSize < 0f) {
+            throw new IllegalArgumentException("Invalid max shadow size " + maxShadowSize +
+                    ". Must be >= 0");
         }
         shadowSize = toEven(shadowSize);
         maxShadowSize = toEven(maxShadowSize);
@@ -184,8 +189,6 @@
     @Override
     public void setColorFilter(ColorFilter cf) {
         mPaint.setColorFilter(cf);
-        mCornerShadowPaint.setColorFilter(cf);
-        mEdgeShadowPaint.setColorFilter(cf);
     }
 
     @Override
@@ -194,6 +197,10 @@
     }
 
     void setCornerRadius(float radius) {
+        if (radius < 0f) {
+            throw new IllegalArgumentException("Invalid radius " + radius +
+                ". Must be >= 0");
+        }
         radius = (int) (radius + .5f);
         if (mCornerRadius == radius) {
             return;
diff --git a/v7/cardview/src/android/support/v7/widget/CardView.java b/v7/cardview/src/android/support/v7/widget/CardView.java
index bc992b8..eb181bc 100644
--- a/v7/cardview/src/android/support/v7/widget/CardView.java
+++ b/v7/cardview/src/android/support/v7/widget/CardView.java
@@ -27,33 +27,33 @@
 /**
  * A FrameLayout with a rounded corner background and shadow.
  * <p>
- * CardView uses <code>elevation</code> property on L for shadows and falls back to a custom shadow
- * implementation on older platforms.
+ * CardView uses <code>elevation</code> property on Lollipop for shadows and falls back to a
+ * custom emulated shadow implementation on older platforms.
  * <p>
- * Due to expensive nature of rounded corner clipping, on platforms before L, CardView does not
- * clip its children that intersect with rounded corners. Instead, it adds padding to avoid such
+ * Due to expensive nature of rounded corner clipping, on platforms before Lollipop, CardView does
+ * not clip its children that intersect with rounded corners. Instead, it adds padding to avoid such
  * intersection (See {@link #setPreventCornerOverlap(boolean)} to change this behavior).
  * <p>
- * Before L, CardView adds padding to its content and draws shadows to that area. This padding
- * amount is equal to <code>maxCardElevation + (1 - cos45) * cornerRadius</code> on the sides and
- * <code>maxCardElevation * 1.5 + (1 - cos45) * cornerRadius</code> on top and bottom.
+ * Before Lollipop, CardView adds padding to its content and draws shadows to that area. This
+ * padding amount is equal to <code>maxCardElevation + (1 - cos45) * cornerRadius</code> on the
+ * sides and <code>maxCardElevation * 1.5 + (1 - cos45) * cornerRadius</code> on top and bottom.
  * <p>
  * Since padding is used to offset content for shadows, you cannot set padding on CardView.
- * Instead,
- * you can use content padding attributes in XML or {@link #setContentPadding(int, int, int, int)}
- * in code to set the padding between the edges of the Card and children of CardView.
+ * Instead, you can use content padding attributes in XML or
+ * {@link #setContentPadding(int, int, int, int)} in code to set the padding between the edges of
+ * the CardView and children of CardView.
  * <p>
  * Note that, if you specify exact dimensions for the CardView, because of the shadows, its content
- * area will be different between platforms before L and after L. By using api version specific
- * resource values, you can avoid these changes. Alternatively, If you want CardView to add inner
- * padding on platforms L and after as well, you can set {@link #setUseCompatPadding(boolean)} to
- * <code>true</code>.
+ * area will be different between platforms before Lollipop and after Lollipop. By using api version
+ * specific resource values, you can avoid these changes. Alternatively, If you want CardView to add
+ * inner padding on platforms Lollipop and after as well, you can call
+ * {@link #setUseCompatPadding(boolean)} and pass <code>true</code>.
  * <p>
  * To change CardView's elevation in a backward compatible way, use
- * {@link #setCardElevation(float)}. CardView will use elevation API on L and before L, it will
- * change the shadow size. To avoid moving the View while shadow size is changing, shadow size is
- * clamped by {@link #getMaxCardElevation()}. If you want to change elevation dynamically, you
- * should call {@link #setMaxCardElevation(float)} when CardView is initialized.
+ * {@link #setCardElevation(float)}. CardView will use elevation API on Lollipop and before
+ * Lollipop, it will change the shadow size. To avoid moving the View while shadow size is changing,
+ * shadow size is clamped by {@link #getMaxCardElevation()}. If you want to change elevation
+ * dynamically, you should call {@link #setMaxCardElevation(float)} when CardView is initialized.
  *
  * @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor
  * @attr ref android.support.v7.cardview.R.styleable#CardView_cardCornerRadius
@@ -116,10 +116,10 @@
     }
 
     /**
-     * Returns whether CardView will add inner padding on platforms L and after.
+     * Returns whether CardView will add inner padding on platforms Lollipop and after.
      *
-     * @return True CardView adds inner padding on platforms L and after to have same dimensions
-     * with platforms before L.
+     * @return <code>true</code> if CardView adds inner padding on platforms Lollipop and after to
+     * have same dimensions with platforms before Lollipop.
      */
     @Override
     public boolean getUseCompatPadding() {
@@ -127,19 +127,19 @@
     }
 
     /**
-     * CardView adds additional padding to draw shadows on platforms before L.
+     * CardView adds additional padding to draw shadows on platforms before Lollipop.
      * <p>
-     * This may cause Cards to have different sizes between L and before L. If you need to align
-     * CardView with other Views, you may need api version specific dimension resources to account
-     * for the changes.
+     * This may cause Cards to have different sizes between Lollipop and before Lollipop. If you
+     * need to align CardView with other Views, you may need api version specific dimension
+     * resources to account for the changes.
      * As an alternative, you can set this flag to <code>true</code> and CardView will add the same
-     * padding values on platforms L and after.
+     * padding values on platforms Lollipop and after.
      * <p>
      * Since setting this flag to true adds unnecessary gaps in the UI, default value is
      * <code>false</code>.
      *
-     * @param useCompatPadding True if CardView should add padding for the shadows on platforms L
-     *                         and above.
+     * @param useCompatPadding <code>true></code> if CardView should add padding for the shadows on
+     *      platforms Lollipop and above.
      * @attr ref android.support.v7.cardview.R.styleable#CardView_cardUseCompatPadding
      */
     public void setUseCompatPadding(boolean useCompatPadding) {
@@ -306,13 +306,13 @@
     /**
      * Updates the backward compatible elevation of the CardView.
      *
-     * @param radius The backward compatible elevation in pixels.
+     * @param elevation The backward compatible elevation in pixels.
      * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation
      * @see #getCardElevation()
      * @see #setMaxCardElevation(float)
      */
-    public void setCardElevation(float radius) {
-        IMPL.setElevation(this, radius);
+    public void setCardElevation(float elevation) {
+        IMPL.setElevation(this, elevation);
     }
 
     /**
@@ -327,24 +327,24 @@
     }
 
     /**
-     * Updates the backward compatible elevation of the CardView.
+     * Updates the backward compatible maximum elevation of the CardView.
      * <p>
-     * Calling this method has no effect if device OS version is L or newer and
+     * Calling this method has no effect if device OS version is Lollipop or newer and
      * {@link #getUseCompatPadding()} is <code>false</code>.
      *
-     * @param radius The backward compatible elevation in pixels.
-     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation
+     * @param maxElevation The backward compatible maximum elevation in pixels.
+     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardMaxElevation
      * @see #setCardElevation(float)
      * @see #getMaxCardElevation()
      */
-    public void setMaxCardElevation(float radius) {
-        IMPL.setMaxElevation(this, radius);
+    public void setMaxCardElevation(float maxElevation) {
+        IMPL.setMaxElevation(this, maxElevation);
     }
 
     /**
-     * Returns the backward compatible elevation of the CardView.
+     * Returns the backward compatible maximum elevation of the CardView.
      *
-     * @return Elevation of the CardView
+     * @return Maximum elevation of the CardView
      * @see #setMaxCardElevation(float)
      * @see #getCardElevation()
      */
@@ -354,9 +354,9 @@
 
     /**
      * Returns whether CardView should add extra padding to content to avoid overlaps with rounded
-     * corners on API versions 20 and below.
+     * corners on pre-Lollipop platforms.
      *
-     * @return True if CardView prevents overlaps with rounded corners on platforms before L.
+     * @return True if CardView prevents overlaps with rounded corners on platforms before Lollipop.
      *         Default value is <code>true</code>.
      */
     @Override
@@ -365,11 +365,11 @@
     }
 
     /**
-     * On API 20 and before, CardView does not clip the bounds of the Card for the rounded corners.
-     * Instead, it adds padding to content so that it won't overlap with the rounded corners.
-     * You can disable this behavior by setting this field to <code>false</code>.
+     * On pre-Lollipop platforms, CardView does not clip the bounds of the Card for the rounded
+     * corners. Instead, it adds padding to content so that it won't overlap with the rounded
+     * corners. You can disable this behavior by setting this field to <code>false</code>.
      * <p>
-     * Setting this value on API 21 and above does not have any effect unless you have enabled
+     * Setting this value on Lollipop and above does not have any effect unless you have enabled
      * compatibility padding.
      *
      * @param preventCornerOverlap Whether CardView should add extra padding to content to avoid
diff --git a/v7/gridlayout/api/23.txt b/v7/gridlayout/api/23.0.0.txt
similarity index 100%
rename from v7/gridlayout/api/23.txt
rename to v7/gridlayout/api/23.0.0.txt
diff --git a/v7/gridlayout/api/23.txt b/v7/gridlayout/api/23.1.0.txt
similarity index 100%
copy from v7/gridlayout/api/23.txt
copy to v7/gridlayout/api/23.1.0.txt
diff --git a/v7/gridlayout/src/android/support/v7/widget/GridLayout.java b/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
index cee59eb..a493911 100644
--- a/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
+++ b/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
@@ -1647,7 +1647,8 @@
             boolean validSolution = true;
             // do a binary search to find the max delta that won't conflict with constraints
             while(deltaMin < deltaMax) {
-                final int delta = (deltaMin + deltaMax) / 2;
+                // cast to long to prevent overflow.
+                final int delta = (int)(((long)deltaMin + deltaMax) / 2);
                 invalidateValues();
                 shareOutDelta(delta, totalWeight);
                 validSolution = solve(getArcs(), a, false);
diff --git a/v7/mediarouter/Android.mk b/v7/mediarouter/Android.mk
index 03f9f99..9bd9960 100644
--- a/v7/mediarouter/Android.mk
+++ b/v7/mediarouter/Android.mk
@@ -30,6 +30,8 @@
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files := $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of JellyBean APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-mediarouter-jellybean
@@ -37,6 +39,8 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, jellybean)
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of JellyBean MR1 APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-mediarouter-jellybean-mr1
@@ -45,6 +49,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-jellybean
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # A helper sub-library that makes direct use of JellyBean MR2 APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-mediarouter-jellybean-mr2
@@ -53,6 +59,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-jellybean-mr1
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # Here is the final static library that apps can link against.
 # The R class is automatically excluded from the generated library.
 # Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -63,14 +71,17 @@
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-jellybean-mr2
 LOCAL_JAVA_LIBRARIES := android-support-v4 android-support-v7-mediarouter-res \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-palette
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+support_module_src_files += $(LOCAL_SRC_FILES)
+
 # API Check
 # ---------------------------------------------
 support_module := $(LOCAL_MODULE)
 support_module_api_dir := $(LOCAL_PATH)/api
 support_module_src_files := $(LOCAL_SRC_FILES)
-support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES) android-support-v7-mediarouter
+support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
 support_module_java_packages := android.support.v7.app android.support.v7.media
 include $(SUPPORT_API_CHECK)
diff --git a/v7/mediarouter/api/23.txt b/v7/mediarouter/api/23.0.0.txt
similarity index 100%
rename from v7/mediarouter/api/23.txt
rename to v7/mediarouter/api/23.0.0.txt
diff --git a/v7/mediarouter/api/23.1.0.txt b/v7/mediarouter/api/23.1.0.txt
new file mode 100644
index 0000000..69fc20e
--- /dev/null
+++ b/v7/mediarouter/api/23.1.0.txt
@@ -0,0 +1,694 @@
+package android.support.v7.app {
+
+  public abstract class ActionBar {
+    ctor public ActionBar();
+    method public abstract void addOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract void addTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract void addTab(android.support.v7.app.ActionBar.Tab, boolean);
+    method public abstract void addTab(android.support.v7.app.ActionBar.Tab, int);
+    method public abstract void addTab(android.support.v7.app.ActionBar.Tab, int, boolean);
+    method public boolean collapseActionView();
+    method public void dispatchMenuVisibilityChanged(boolean);
+    method public abstract android.view.View getCustomView();
+    method public abstract int getDisplayOptions();
+    method public float getElevation();
+    method public abstract int getHeight();
+    method public int getHideOffset();
+    method public abstract int getNavigationItemCount();
+    method public abstract int getNavigationMode();
+    method public abstract int getSelectedNavigationIndex();
+    method public abstract android.support.v7.app.ActionBar.Tab getSelectedTab();
+    method public abstract java.lang.CharSequence getSubtitle();
+    method public abstract android.support.v7.app.ActionBar.Tab getTabAt(int);
+    method public abstract int getTabCount();
+    method public android.content.Context getThemedContext();
+    method public abstract java.lang.CharSequence getTitle();
+    method public abstract void hide();
+    method public boolean invalidateOptionsMenu();
+    method public boolean isHideOnContentScrollEnabled();
+    method public abstract boolean isShowing();
+    method public boolean isTitleTruncated();
+    method public abstract android.support.v7.app.ActionBar.Tab newTab();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public boolean onKeyShortcut(int, android.view.KeyEvent);
+    method public boolean onMenuKeyEvent(android.view.KeyEvent);
+    method public boolean openOptionsMenu();
+    method public abstract void removeAllTabs();
+    method public abstract void removeOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+    method public abstract void removeTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract void removeTabAt(int);
+    method public abstract void selectTab(android.support.v7.app.ActionBar.Tab);
+    method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setCustomView(android.view.View);
+    method public abstract void setCustomView(android.view.View, android.support.v7.app.ActionBar.LayoutParams);
+    method public abstract void setCustomView(int);
+    method public void setDefaultDisplayHomeAsUpEnabled(boolean);
+    method public abstract void setDisplayHomeAsUpEnabled(boolean);
+    method public abstract void setDisplayOptions(int);
+    method public abstract void setDisplayOptions(int, int);
+    method public abstract void setDisplayShowCustomEnabled(boolean);
+    method public abstract void setDisplayShowHomeEnabled(boolean);
+    method public abstract void setDisplayShowTitleEnabled(boolean);
+    method public abstract void setDisplayUseLogoEnabled(boolean);
+    method public void setElevation(float);
+    method public void setHideOffset(int);
+    method public void setHideOnContentScrollEnabled(boolean);
+    method public void setHomeActionContentDescription(java.lang.CharSequence);
+    method public void setHomeActionContentDescription(int);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setHomeButtonEnabled(boolean);
+    method public abstract void setIcon(int);
+    method public abstract void setIcon(android.graphics.drawable.Drawable);
+    method public abstract void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.support.v7.app.ActionBar.OnNavigationListener);
+    method public abstract void setLogo(int);
+    method public abstract void setLogo(android.graphics.drawable.Drawable);
+    method public abstract void setNavigationMode(int);
+    method public abstract void setSelectedNavigationItem(int);
+    method public void setShowHideAnimationEnabled(boolean);
+    method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public abstract void setSubtitle(java.lang.CharSequence);
+    method public abstract void setSubtitle(int);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract void setTitle(int);
+    method public void setWindowTitle(java.lang.CharSequence);
+    method public abstract void show();
+    method public android.support.v7.view.ActionMode startActionMode(android.support.v7.view.ActionMode.Callback);
+    field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
+    field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
+    field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
+    field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
+    field public static final int DISPLAY_USE_LOGO = 1; // 0x1
+    field public static final int NAVIGATION_MODE_LIST = 1; // 0x1
+    field public static final int NAVIGATION_MODE_STANDARD = 0; // 0x0
+    field public static final int NAVIGATION_MODE_TABS = 2; // 0x2
+  }
+
+  public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionBar.LayoutParams(int, int);
+    ctor public ActionBar.LayoutParams(int, int, int);
+    ctor public ActionBar.LayoutParams(int);
+    ctor public ActionBar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+    ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
+    field public int gravity;
+  }
+
+  public static abstract interface ActionBar.OnMenuVisibilityListener {
+    method public abstract void onMenuVisibilityChanged(boolean);
+  }
+
+  public static abstract interface ActionBar.OnNavigationListener {
+    method public abstract boolean onNavigationItemSelected(int, long);
+  }
+
+  public static abstract class ActionBar.Tab {
+    ctor public ActionBar.Tab();
+    method public abstract java.lang.CharSequence getContentDescription();
+    method public abstract android.view.View getCustomView();
+    method public abstract android.graphics.drawable.Drawable getIcon();
+    method public abstract int getPosition();
+    method public abstract java.lang.Object getTag();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract void select();
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(android.view.View);
+    method public abstract android.support.v7.app.ActionBar.Tab setCustomView(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
+    method public abstract android.support.v7.app.ActionBar.Tab setIcon(int);
+    method public abstract android.support.v7.app.ActionBar.Tab setTabListener(android.support.v7.app.ActionBar.TabListener);
+    method public abstract android.support.v7.app.ActionBar.Tab setTag(java.lang.Object);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(java.lang.CharSequence);
+    method public abstract android.support.v7.app.ActionBar.Tab setText(int);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static abstract interface ActionBar.TabListener {
+    method public abstract void onTabReselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabSelected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+    method public abstract void onTabUnselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+  }
+
+  public class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int);
+    ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, android.support.v7.widget.Toolbar, int, int);
+    method public android.view.View.OnClickListener getToolbarNavigationClickListener();
+    method public boolean isDrawerIndicatorEnabled();
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public void setDrawerIndicatorEnabled(boolean);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
+    method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
+    method public void syncState();
+  }
+
+  public static abstract interface ActionBarDrawerToggle.Delegate {
+    method public abstract android.content.Context getActionBarThemedContext();
+    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+    method public abstract boolean isNavigationVisible();
+    method public abstract void setActionBarDescription(int);
+    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+  }
+
+  public class AlertDialog extends android.support.v7.app.AppCompatDialog implements android.content.DialogInterface {
+    ctor protected AlertDialog(android.content.Context);
+    ctor protected AlertDialog(android.content.Context, int);
+    ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.widget.Button getButton(int);
+    method public android.widget.ListView getListView();
+    method public void setButton(int, java.lang.CharSequence, android.os.Message);
+    method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public void setCustomTitle(android.view.View);
+    method public void setIcon(int);
+    method public void setIcon(android.graphics.drawable.Drawable);
+    method public void setIconAttribute(int);
+    method public void setMessage(java.lang.CharSequence);
+    method public void setView(android.view.View);
+    method public void setView(android.view.View, int, int, int, int);
+  }
+
+  public abstract interface AppCompatCallback {
+    method public abstract void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public abstract void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public abstract android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+  }
+
+  public abstract class AppCompatDelegate {
+    method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Activity, android.support.v7.app.AppCompatCallback);
+    method public static android.support.v7.app.AppCompatDelegate create(android.app.Dialog, android.support.v7.app.AppCompatCallback);
+    method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+    method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+    method public abstract android.view.MenuInflater getMenuInflater();
+    method public abstract android.support.v7.app.ActionBar getSupportActionBar();
+    method public abstract boolean hasWindowFeature(int);
+    method public abstract void installViewFactory();
+    method public abstract void invalidateOptionsMenu();
+    method public abstract boolean isHandleNativeActionModesEnabled();
+    method public abstract void onConfigurationChanged(android.content.res.Configuration);
+    method public abstract void onCreate(android.os.Bundle);
+    method public abstract void onDestroy();
+    method public abstract void onPostCreate(android.os.Bundle);
+    method public abstract void onPostResume();
+    method public abstract void onStop();
+    method public abstract boolean requestWindowFeature(int);
+    method public abstract void setContentView(android.view.View);
+    method public abstract void setContentView(int);
+    method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract void setHandleNativeActionModesEnabled(boolean);
+    method public abstract void setSupportActionBar(android.support.v7.widget.Toolbar);
+    method public abstract void setTitle(java.lang.CharSequence);
+    method public abstract android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+    field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
+    field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
+  }
+
+  public class AppCompatDialog extends android.app.Dialog implements android.support.v7.app.AppCompatCallback {
+    ctor public AppCompatDialog(android.content.Context);
+    ctor public AppCompatDialog(android.content.Context, int);
+    ctor protected AppCompatDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    method public android.support.v7.app.AppCompatDelegate getDelegate();
+    method public android.support.v7.app.ActionBar getSupportActionBar();
+    method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+    method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+    method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+    method public boolean supportRequestWindowFeature(int);
+  }
+
+  public class MediaRouteActionProvider extends android.support.v4.view.ActionProvider {
+    ctor public MediaRouteActionProvider(android.content.Context);
+    method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+    method public android.support.v7.app.MediaRouteButton getMediaRouteButton();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.view.View onCreateActionView();
+    method public android.support.v7.app.MediaRouteButton onCreateMediaRouteButton();
+    method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteButton extends android.view.View {
+    ctor public MediaRouteButton(android.content.Context);
+    ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet);
+    ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet, int);
+    method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+    method public void setRemoteIndicatorDrawable(android.graphics.drawable.Drawable);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+    method public boolean showDialog();
+  }
+
+  public class MediaRouteChooserDialog extends android.app.Dialog {
+    ctor public MediaRouteChooserDialog(android.content.Context);
+    ctor public MediaRouteChooserDialog(android.content.Context, int);
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public boolean onFilterRoute(android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onFilterRoutes(java.util.List<android.support.v7.media.MediaRouter.RouteInfo>);
+    method public void refreshRoutes();
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteChooserDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public MediaRouteChooserDialogFragment();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.support.v7.app.MediaRouteChooserDialog onCreateChooserDialog(android.content.Context, android.os.Bundle);
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+  public class MediaRouteControllerDialog extends android.support.v7.app.AlertDialog {
+    ctor public MediaRouteControllerDialog(android.content.Context);
+    ctor public MediaRouteControllerDialog(android.content.Context, int);
+    method public android.view.View getMediaControlView();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSession();
+    method public android.support.v7.media.MediaRouter.RouteInfo getRoute();
+    method public boolean isVolumeControlEnabled();
+    method public android.view.View onCreateMediaControlView(android.os.Bundle);
+    method public void setVolumeControlEnabled(boolean);
+  }
+
+  public class MediaRouteControllerDialogFragment extends android.support.v4.app.DialogFragment {
+    ctor public MediaRouteControllerDialogFragment();
+    method public android.support.v7.app.MediaRouteControllerDialog onCreateControllerDialog(android.content.Context, android.os.Bundle);
+  }
+
+  public class MediaRouteDialogFactory {
+    ctor public MediaRouteDialogFactory();
+    method public static android.support.v7.app.MediaRouteDialogFactory getDefault();
+    method public android.support.v7.app.MediaRouteChooserDialogFragment onCreateChooserDialogFragment();
+    method public android.support.v7.app.MediaRouteControllerDialogFragment onCreateControllerDialogFragment();
+  }
+
+  public class MediaRouteDiscoveryFragment extends android.support.v4.app.Fragment {
+    ctor public MediaRouteDiscoveryFragment();
+    method public android.support.v7.media.MediaRouter getMediaRouter();
+    method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+    method public android.support.v7.media.MediaRouter.Callback onCreateCallback();
+    method public int onPrepareCallbackFlags();
+    method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+  }
+
+}
+
+package android.support.v7.media {
+
+  public final class MediaControlIntent {
+    field public static final java.lang.String ACTION_END_SESSION = "android.media.intent.action.END_SESSION";
+    field public static final java.lang.String ACTION_ENQUEUE = "android.media.intent.action.ENQUEUE";
+    field public static final java.lang.String ACTION_GET_SESSION_STATUS = "android.media.intent.action.GET_SESSION_STATUS";
+    field public static final java.lang.String ACTION_GET_STATUS = "android.media.intent.action.GET_STATUS";
+    field public static final java.lang.String ACTION_PAUSE = "android.media.intent.action.PAUSE";
+    field public static final java.lang.String ACTION_PLAY = "android.media.intent.action.PLAY";
+    field public static final java.lang.String ACTION_REMOVE = "android.media.intent.action.REMOVE";
+    field public static final java.lang.String ACTION_RESUME = "android.media.intent.action.RESUME";
+    field public static final java.lang.String ACTION_SEEK = "android.media.intent.action.SEEK";
+    field public static final java.lang.String ACTION_START_SESSION = "android.media.intent.action.START_SESSION";
+    field public static final java.lang.String ACTION_STOP = "android.media.intent.action.STOP";
+    field public static final java.lang.String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+    field public static final java.lang.String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
+    field public static final java.lang.String CATEGORY_REMOTE_PLAYBACK = "android.media.intent.category.REMOTE_PLAYBACK";
+    field public static final int ERROR_INVALID_ITEM_ID = 3; // 0x3
+    field public static final int ERROR_INVALID_SESSION_ID = 2; // 0x2
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int ERROR_UNSUPPORTED_OPERATION = 1; // 0x1
+    field public static final java.lang.String EXTRA_ERROR_CODE = "android.media.intent.extra.ERROR_CODE";
+    field public static final java.lang.String EXTRA_ITEM_CONTENT_POSITION = "android.media.intent.extra.ITEM_POSITION";
+    field public static final java.lang.String EXTRA_ITEM_HTTP_HEADERS = "android.media.intent.extra.HTTP_HEADERS";
+    field public static final java.lang.String EXTRA_ITEM_ID = "android.media.intent.extra.ITEM_ID";
+    field public static final java.lang.String EXTRA_ITEM_METADATA = "android.media.intent.extra.ITEM_METADATA";
+    field public static final java.lang.String EXTRA_ITEM_STATUS = "android.media.intent.extra.ITEM_STATUS";
+    field public static final java.lang.String EXTRA_ITEM_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.ITEM_STATUS_UPDATE_RECEIVER";
+    field public static final java.lang.String EXTRA_SESSION_ID = "android.media.intent.extra.SESSION_ID";
+    field public static final java.lang.String EXTRA_SESSION_STATUS = "android.media.intent.extra.SESSION_STATUS";
+    field public static final java.lang.String EXTRA_SESSION_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.SESSION_STATUS_UPDATE_RECEIVER";
+  }
+
+  public final class MediaItemMetadata {
+    field public static final java.lang.String KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String KEY_ALBUM_TITLE = "android.media.metadata.ALBUM_TITLE";
+    field public static final java.lang.String KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String KEY_ARTWORK_URI = "android.media.metadata.ARTWORK_URI";
+    field public static final java.lang.String KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public final class MediaItemStatus {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaItemStatus fromBundle(android.os.Bundle);
+    method public long getContentDuration();
+    method public long getContentPosition();
+    method public android.os.Bundle getExtras();
+    method public int getPlaybackState();
+    method public long getTimestamp();
+    field public static final java.lang.String EXTRA_HTTP_RESPONSE_HEADERS = "android.media.status.extra.HTTP_RESPONSE_HEADERS";
+    field public static final java.lang.String EXTRA_HTTP_STATUS_CODE = "android.media.status.extra.HTTP_STATUS_CODE";
+    field public static final int PLAYBACK_STATE_BUFFERING = 3; // 0x3
+    field public static final int PLAYBACK_STATE_CANCELED = 5; // 0x5
+    field public static final int PLAYBACK_STATE_ERROR = 7; // 0x7
+    field public static final int PLAYBACK_STATE_FINISHED = 4; // 0x4
+    field public static final int PLAYBACK_STATE_INVALIDATED = 6; // 0x6
+    field public static final int PLAYBACK_STATE_PAUSED = 2; // 0x2
+    field public static final int PLAYBACK_STATE_PENDING = 0; // 0x0
+    field public static final int PLAYBACK_STATE_PLAYING = 1; // 0x1
+  }
+
+  public static final class MediaItemStatus.Builder {
+    ctor public MediaItemStatus.Builder(int);
+    ctor public MediaItemStatus.Builder(android.support.v7.media.MediaItemStatus);
+    method public android.support.v7.media.MediaItemStatus build();
+    method public android.support.v7.media.MediaItemStatus.Builder setContentDuration(long);
+    method public android.support.v7.media.MediaItemStatus.Builder setContentPosition(long);
+    method public android.support.v7.media.MediaItemStatus.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaItemStatus.Builder setPlaybackState(int);
+    method public android.support.v7.media.MediaItemStatus.Builder setTimestamp(long);
+  }
+
+  public final class MediaRouteDescriptor {
+    method public android.os.Bundle asBundle();
+    method public boolean canDisconnectAndKeepPlaying();
+    method public static android.support.v7.media.MediaRouteDescriptor fromBundle(android.os.Bundle);
+    method public int getConnectionState();
+    method public java.util.List<android.content.IntentFilter> getControlFilters();
+    method public java.lang.String getDescription();
+    method public int getDeviceType();
+    method public android.os.Bundle getExtras();
+    method public java.util.List<java.lang.String> getGroupMemberIds();
+    method public android.net.Uri getIconUri();
+    method public java.lang.String getId();
+    method public java.lang.String getName();
+    method public int getPlaybackStream();
+    method public int getPlaybackType();
+    method public int getPresentationDisplayId();
+    method public android.content.IntentSender getSettingsActivity();
+    method public int getVolume();
+    method public int getVolumeHandling();
+    method public int getVolumeMax();
+    method public deprecated boolean isConnecting();
+    method public boolean isEnabled();
+    method public boolean isValid();
+  }
+
+  public static final class MediaRouteDescriptor.Builder {
+    ctor public MediaRouteDescriptor.Builder(java.lang.String, java.lang.String);
+    ctor public MediaRouteDescriptor.Builder(android.support.v7.media.MediaRouteDescriptor);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilter(android.content.IntentFilter);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilters(java.util.Collection<android.content.IntentFilter>);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addGroupMemberId(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder addGroupMemberIds(java.util.Collection<java.lang.String>);
+    method public android.support.v7.media.MediaRouteDescriptor build();
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
+    method public deprecated android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setConnectionState(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setDescription(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setDeviceType(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setEnabled(boolean);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setIconUri(android.net.Uri);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setId(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setName(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackStream(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackType(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setPresentationDisplayId(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setSettingsActivity(android.content.IntentSender);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolume(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeHandling(int);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeMax(int);
+  }
+
+  public final class MediaRouteDiscoveryRequest {
+    ctor public MediaRouteDiscoveryRequest(android.support.v7.media.MediaRouteSelector, boolean);
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaRouteDiscoveryRequest fromBundle(android.os.Bundle);
+    method public android.support.v7.media.MediaRouteSelector getSelector();
+    method public boolean isActiveScan();
+    method public boolean isValid();
+  }
+
+  public abstract class MediaRouteProvider {
+    ctor public MediaRouteProvider(android.content.Context);
+    method public final android.content.Context getContext();
+    method public final android.support.v7.media.MediaRouteProviderDescriptor getDescriptor();
+    method public final android.support.v7.media.MediaRouteDiscoveryRequest getDiscoveryRequest();
+    method public final android.os.Handler getHandler();
+    method public final android.support.v7.media.MediaRouteProvider.ProviderMetadata getMetadata();
+    method public android.support.v7.media.MediaRouteProvider.RouteController onCreateRouteController(java.lang.String);
+    method public void onDiscoveryRequestChanged(android.support.v7.media.MediaRouteDiscoveryRequest);
+    method public final void setCallback(android.support.v7.media.MediaRouteProvider.Callback);
+    method public final void setDescriptor(android.support.v7.media.MediaRouteProviderDescriptor);
+    method public final void setDiscoveryRequest(android.support.v7.media.MediaRouteDiscoveryRequest);
+  }
+
+  public static abstract class MediaRouteProvider.Callback {
+    ctor public MediaRouteProvider.Callback();
+    method public void onDescriptorChanged(android.support.v7.media.MediaRouteProvider, android.support.v7.media.MediaRouteProviderDescriptor);
+  }
+
+  public static final class MediaRouteProvider.ProviderMetadata {
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getPackageName();
+  }
+
+  public static abstract class MediaRouteProvider.RouteController {
+    ctor public MediaRouteProvider.RouteController();
+    method public boolean onControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+    method public void onRelease();
+    method public void onSelect();
+    method public void onSetVolume(int);
+    method public void onUnselect();
+    method public void onUnselect(int);
+    method public void onUpdateVolume(int);
+  }
+
+  public final class MediaRouteProviderDescriptor {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaRouteProviderDescriptor fromBundle(android.os.Bundle);
+    method public java.util.List<android.support.v7.media.MediaRouteDescriptor> getRoutes();
+    method public boolean isValid();
+  }
+
+  public static final class MediaRouteProviderDescriptor.Builder {
+    ctor public MediaRouteProviderDescriptor.Builder();
+    ctor public MediaRouteProviderDescriptor.Builder(android.support.v7.media.MediaRouteProviderDescriptor);
+    method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoute(android.support.v7.media.MediaRouteDescriptor);
+    method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoutes(java.util.Collection<android.support.v7.media.MediaRouteDescriptor>);
+    method public android.support.v7.media.MediaRouteProviderDescriptor build();
+  }
+
+  public abstract class MediaRouteProviderService extends android.app.Service {
+    ctor public MediaRouteProviderService();
+    method public android.support.v7.media.MediaRouteProvider getMediaRouteProvider();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.support.v7.media.MediaRouteProvider onCreateMediaRouteProvider();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaRouteProviderService";
+  }
+
+  public final class MediaRouteSelector {
+    method public android.os.Bundle asBundle();
+    method public boolean contains(android.support.v7.media.MediaRouteSelector);
+    method public static android.support.v7.media.MediaRouteSelector fromBundle(android.os.Bundle);
+    method public java.util.List<java.lang.String> getControlCategories();
+    method public boolean hasControlCategory(java.lang.String);
+    method public boolean isEmpty();
+    method public boolean isValid();
+    method public boolean matchesControlFilters(java.util.List<android.content.IntentFilter>);
+    field public static final android.support.v7.media.MediaRouteSelector EMPTY;
+  }
+
+  public static final class MediaRouteSelector.Builder {
+    ctor public MediaRouteSelector.Builder();
+    ctor public MediaRouteSelector.Builder(android.support.v7.media.MediaRouteSelector);
+    method public android.support.v7.media.MediaRouteSelector.Builder addControlCategories(java.util.Collection<java.lang.String>);
+    method public android.support.v7.media.MediaRouteSelector.Builder addControlCategory(java.lang.String);
+    method public android.support.v7.media.MediaRouteSelector.Builder addSelector(android.support.v7.media.MediaRouteSelector);
+    method public android.support.v7.media.MediaRouteSelector build();
+  }
+
+  public final class MediaRouter {
+    method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback);
+    method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback, int);
+    method public void addProvider(android.support.v7.media.MediaRouteProvider);
+    method public void addRemoteControlClient(java.lang.Object);
+    method public android.support.v7.media.MediaRouter.RouteInfo getDefaultRoute();
+    method public static android.support.v7.media.MediaRouter getInstance(android.content.Context);
+    method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSessionToken();
+    method public java.util.List<android.support.v7.media.MediaRouter.ProviderInfo> getProviders();
+    method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+    method public android.support.v7.media.MediaRouter.RouteInfo getSelectedRoute();
+    method public boolean isRouteAvailable(android.support.v7.media.MediaRouteSelector, int);
+    method public void removeCallback(android.support.v7.media.MediaRouter.Callback);
+    method public void removeProvider(android.support.v7.media.MediaRouteProvider);
+    method public void removeRemoteControlClient(java.lang.Object);
+    method public void selectRoute(android.support.v7.media.MediaRouter.RouteInfo);
+    method public void setMediaSession(java.lang.Object);
+    method public void setMediaSessionCompat(android.support.v4.media.session.MediaSessionCompat);
+    method public void unselect(int);
+    method public android.support.v7.media.MediaRouter.RouteInfo updateSelectedRoute(android.support.v7.media.MediaRouteSelector);
+    field public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1; // 0x1
+    field public static final int AVAILABILITY_FLAG_REQUIRE_MATCH = 2; // 0x2
+    field public static final int CALLBACK_FLAG_FORCE_DISCOVERY = 8; // 0x8
+    field public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1; // 0x1
+    field public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 4; // 0x4
+    field public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 2; // 0x2
+    field public static final int UNSELECT_REASON_DISCONNECTED = 1; // 0x1
+    field public static final int UNSELECT_REASON_ROUTE_CHANGED = 3; // 0x3
+    field public static final int UNSELECT_REASON_STOPPED = 2; // 0x2
+    field public static final int UNSELECT_REASON_UNKNOWN = 0; // 0x0
+  }
+
+  public static abstract class MediaRouter.Callback {
+    ctor public MediaRouter.Callback();
+    method public void onProviderAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onProviderChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onProviderRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+    method public void onRouteAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRoutePresentationDisplayChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteSelected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void onRouteVolumeChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+  }
+
+  public static abstract class MediaRouter.ControlRequestCallback {
+    ctor public MediaRouter.ControlRequestCallback();
+    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onResult(android.os.Bundle);
+  }
+
+  public static final class MediaRouter.ProviderInfo {
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getPackageName();
+    method public android.support.v7.media.MediaRouteProvider getProviderInstance();
+    method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+  }
+
+  public static class MediaRouter.RouteGroup extends android.support.v7.media.MediaRouter.RouteInfo {
+    method public android.support.v7.media.MediaRouter.RouteInfo getRouteAt(int);
+    method public int getRouteCount();
+    method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+  }
+
+  public static class MediaRouter.RouteInfo {
+    method public boolean canDisconnect();
+    method public int getConnectionState();
+    method public java.util.List<android.content.IntentFilter> getControlFilters();
+    method public java.lang.String getDescription();
+    method public int getDeviceType();
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getIconUri();
+    method public java.lang.String getId();
+    method public java.lang.String getName();
+    method public int getPlaybackStream();
+    method public int getPlaybackType();
+    method public android.view.Display getPresentationDisplay();
+    method public android.support.v7.media.MediaRouter.ProviderInfo getProvider();
+    method public android.content.IntentSender getSettingsIntent();
+    method public int getVolume();
+    method public int getVolumeHandling();
+    method public int getVolumeMax();
+    method public boolean isConnecting();
+    method public boolean isDefault();
+    method public boolean isEnabled();
+    method public boolean isSelected();
+    method public boolean matchesSelector(android.support.v7.media.MediaRouteSelector);
+    method public void requestSetVolume(int);
+    method public void requestUpdateVolume(int);
+    method public void select();
+    method public void sendControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+    method public boolean supportsControlAction(java.lang.String, java.lang.String);
+    method public boolean supportsControlCategory(java.lang.String);
+    method public boolean supportsControlRequest(android.content.Intent);
+    field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+    field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+    field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+    field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+    field public static final int DEVICE_TYPE_TV = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
+    field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
+    field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
+    field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1
+  }
+
+  public final class MediaSessionStatus {
+    method public android.os.Bundle asBundle();
+    method public static android.support.v7.media.MediaSessionStatus fromBundle(android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public int getSessionState();
+    method public long getTimestamp();
+    method public boolean isQueuePaused();
+    field public static final int SESSION_STATE_ACTIVE = 0; // 0x0
+    field public static final int SESSION_STATE_ENDED = 1; // 0x1
+    field public static final int SESSION_STATE_INVALIDATED = 2; // 0x2
+  }
+
+  public static final class MediaSessionStatus.Builder {
+    ctor public MediaSessionStatus.Builder(int);
+    ctor public MediaSessionStatus.Builder(android.support.v7.media.MediaSessionStatus);
+    method public android.support.v7.media.MediaSessionStatus build();
+    method public android.support.v7.media.MediaSessionStatus.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaSessionStatus.Builder setQueuePaused(boolean);
+    method public android.support.v7.media.MediaSessionStatus.Builder setSessionState(int);
+    method public android.support.v7.media.MediaSessionStatus.Builder setTimestamp(long);
+  }
+
+  public class RemotePlaybackClient {
+    ctor public RemotePlaybackClient(android.content.Context, android.support.v7.media.MediaRouter.RouteInfo);
+    method public void endSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void enqueue(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public java.lang.String getSessionId();
+    method public void getSessionStatus(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void getStatus(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public boolean hasSession();
+    method public boolean isQueuingSupported();
+    method public boolean isRemotePlaybackSupported();
+    method public boolean isSessionManagementSupported();
+    method public void pause(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void play(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void release();
+    method public void remove(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void resume(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void seek(java.lang.String, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+    method public void setSessionId(java.lang.String);
+    method public void setStatusCallback(android.support.v7.media.RemotePlaybackClient.StatusCallback);
+    method public void startSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+    method public void stop(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+  }
+
+  public static abstract class RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.ActionCallback();
+    method public void onError(java.lang.String, int, android.os.Bundle);
+  }
+
+  public static abstract class RemotePlaybackClient.ItemActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.ItemActionCallback();
+    method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+  }
+
+  public static abstract class RemotePlaybackClient.SessionActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+    ctor public RemotePlaybackClient.SessionActionCallback();
+    method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+  }
+
+  public static abstract class RemotePlaybackClient.StatusCallback {
+    ctor public RemotePlaybackClient.StatusCallback();
+    method public void onItemStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+    method public void onSessionChanged(java.lang.String);
+    method public void onSessionStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+  }
+
+}
+
diff --git a/v7/mediarouter/api/current.txt b/v7/mediarouter/api/current.txt
index 95fc9d2..92bbbb3 100644
--- a/v7/mediarouter/api/current.txt
+++ b/v7/mediarouter/api/current.txt
@@ -381,9 +381,12 @@
     method public android.os.Bundle asBundle();
     method public boolean canDisconnectAndKeepPlaying();
     method public static android.support.v7.media.MediaRouteDescriptor fromBundle(android.os.Bundle);
+    method public int getConnectionState();
     method public java.util.List<android.content.IntentFilter> getControlFilters();
     method public java.lang.String getDescription();
+    method public int getDeviceType();
     method public android.os.Bundle getExtras();
+    method public android.net.Uri getIconUri();
     method public java.lang.String getId();
     method public java.lang.String getName();
     method public int getPlaybackStream();
@@ -393,7 +396,7 @@
     method public int getVolume();
     method public int getVolumeHandling();
     method public int getVolumeMax();
-    method public boolean isConnecting();
+    method public deprecated boolean isConnecting();
     method public boolean isEnabled();
     method public boolean isValid();
   }
@@ -405,10 +408,13 @@
     method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilters(java.util.Collection<android.content.IntentFilter>);
     method public android.support.v7.media.MediaRouteDescriptor build();
     method public android.support.v7.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
-    method public android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+    method public deprecated android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setConnectionState(int);
     method public android.support.v7.media.MediaRouteDescriptor.Builder setDescription(java.lang.String);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setDeviceType(int);
     method public android.support.v7.media.MediaRouteDescriptor.Builder setEnabled(boolean);
     method public android.support.v7.media.MediaRouteDescriptor.Builder setExtras(android.os.Bundle);
+    method public android.support.v7.media.MediaRouteDescriptor.Builder setIconUri(android.net.Uri);
     method public android.support.v7.media.MediaRouteDescriptor.Builder setId(java.lang.String);
     method public android.support.v7.media.MediaRouteDescriptor.Builder setName(java.lang.String);
     method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackStream(int);
@@ -567,11 +573,14 @@
     method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
   }
 
-  public static final class MediaRouter.RouteInfo {
+  public static class MediaRouter.RouteInfo {
     method public boolean canDisconnect();
+    method public int getConnectionState();
     method public java.util.List<android.content.IntentFilter> getControlFilters();
     method public java.lang.String getDescription();
+    method public int getDeviceType();
     method public android.os.Bundle getExtras();
+    method public android.net.Uri getIconUri();
     method public java.lang.String getId();
     method public java.lang.String getName();
     method public int getPlaybackStream();
@@ -594,6 +603,11 @@
     method public boolean supportsControlAction(java.lang.String, java.lang.String);
     method public boolean supportsControlCategory(java.lang.String);
     method public boolean supportsControlRequest(android.content.Intent);
+    field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+    field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+    field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+    field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+    field public static final int DEVICE_TYPE_TV = 1; // 0x1
     field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
     field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
     field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index a304746..48f4750 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -5,6 +5,7 @@
 
 dependencies {
     compile project(':support-appcompat-v7')
+    compile project(':support-palette-v7')
 }
 
 // some of the source requires compiling against a newer API.
@@ -56,6 +57,11 @@
         androidTest.java.srcDir 'tests/src'
     }
 
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_7
+        targetCompatibility JavaVersion.VERSION_1_7
+    }
+
     lintOptions {
         // TODO: fix errors and reenable.
         abortOnError false
@@ -111,7 +117,7 @@
             }
 
             pom.project {
-                name 'Android Support Library v4'
+                name 'Android MediaRouter Support Library'
                 description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
                 url 'http://developer.android.com/tools/extras/support-library.html'
                 inceptionYear '2011'
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png
new file mode 100644
index 0000000..71db6b4
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..d7c8252
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..0493c80
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..fce1884
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-hdpi/ic_cast_grey.png
new file mode 100644
index 0000000..f0960f8
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-hdpi/ic_cast_white.png
new file mode 100644
index 0000000..60d3915
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_close_dark.png
new file mode 100644
index 0000000..ceb1a1e
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_close_light.png b/v7/mediarouter/res/drawable-hdpi/ic_close_light.png
new file mode 100644
index 0000000..1a9cd75
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png
index 81c32fe..7192ad4 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png
index 864d8d2..bb707ea 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png
index 568ae86..547ef30 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_play_light.png b/v7/mediarouter/res/drawable-hdpi/ic_play_light.png
index e278033..5345ee3 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_setting_dark.png
deleted file mode 100644
index 3248ad1..0000000
--- a/v7/mediarouter/res/drawable-hdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-hdpi/ic_setting_light.png
deleted file mode 100644
index c39fc1f..0000000
--- a/v7/mediarouter/res/drawable-hdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..0e1da44
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..b90bb2f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..afdb9c1
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_light.png
new file mode 100755
index 0000000..e2c88be
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_tv_dark.png
new file mode 100755
index 0000000..d1335f6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-hdpi/ic_tv_light.png
new file mode 100755
index 0000000..7330f56
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png
new file mode 100644
index 0000000..dc1200e
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..2cf7e0c
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..ddc8789
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..27a8a71
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-mdpi/ic_cast_grey.png
new file mode 100644
index 0000000..35ffd60
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-mdpi/ic_cast_white.png
new file mode 100644
index 0000000..d62923f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_close_dark.png
new file mode 100644
index 0000000..af7f828
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_close_light.png b/v7/mediarouter/res/drawable-mdpi/ic_close_light.png
new file mode 100644
index 0000000..40a1a84
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png
index c4218a4..f49aed7 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png
index ab26a30..74068ea 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png
index 4446faa..a3c80e7 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_play_light.png b/v7/mediarouter/res/drawable-mdpi/ic_play_light.png
index 55b8c5e..f208795 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_setting_dark.png
deleted file mode 100644
index 1f0ba42..0000000
--- a/v7/mediarouter/res/drawable-mdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-mdpi/ic_setting_light.png
deleted file mode 100644
index 3744fe4e..0000000
--- a/v7/mediarouter/res/drawable-mdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..7cc9845
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..4db7209
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..d26bb58
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_light.png
new file mode 100755
index 0000000..ae8d47f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_tv_dark.png
new file mode 100755
index 0000000..82358a9
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-mdpi/ic_tv_light.png
new file mode 100755
index 0000000..ba3f3d5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png
new file mode 100644
index 0000000..b5c899f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..4778e00
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..c57b9d6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..920f5ca
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-xhdpi/ic_cast_grey.png
new file mode 100644
index 0000000..dba8992
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-xhdpi/ic_cast_white.png
new file mode 100644
index 0000000..f5f7c14
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_close_dark.png
new file mode 100644
index 0000000..b7c7ffd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_close_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_close_light.png
new file mode 100644
index 0000000..6bc4372
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png
index bd7ec0f..660ac65 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png
index e79d7d7..792104ff 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png
index 9a5d45f..be5c062 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png
index acaeca6..d12d495 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_setting_dark.png
deleted file mode 100644
index 8db5dbb..0000000
--- a/v7/mediarouter/res/drawable-xhdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_setting_light.png
deleted file mode 100644
index bfc30ef..0000000
--- a/v7/mediarouter/res/drawable-xhdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..8f8a552
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..6227ca2
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..82599f5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_light.png
new file mode 100755
index 0000000..74f9f6d
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_tv_dark.png
new file mode 100755
index 0000000..cef8ac5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_tv_light.png
new file mode 100755
index 0000000..3131256
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png
new file mode 100644
index 0000000..0546539
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..8e38265
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..8e9aa70
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..860c758
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_grey.png
new file mode 100644
index 0000000..7582751
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_white.png
new file mode 100644
index 0000000..7a7673fb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_close_dark.png
new file mode 100644
index 0000000..6b717e0
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_close_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_close_light.png
new file mode 100644
index 0000000..51b4401
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png
index 2a96557..3ea7e03 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png
index bf2560f..dc63538 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png
index 1ec1995..2745c3a 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png
index a5bd8df..1c57756b 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_setting_dark.png
deleted file mode 100644
index 1d58233..0000000
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_setting_light.png
deleted file mode 100644
index 43c9b99b..0000000
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..874c961
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..6869bdc
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..35de6f4
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_light.png
new file mode 100755
index 0000000..65ee187
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_dark.png
new file mode 100755
index 0000000..a6a4858
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_light.png
new file mode 100755
index 0000000..4ca6787
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_grey.png
new file mode 100644
index 0000000..d124cb8
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_white.png
new file mode 100644
index 0000000..bb3539c
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_close_light.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_close_light.png
new file mode 100644
index 0000000..df42fee
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00000.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00000.png
new file mode 100644
index 0000000..16e4cbc
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00000.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00001.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00001.png
new file mode 100644
index 0000000..6cc54b6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00001.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00002.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00002.png
new file mode 100644
index 0000000..ae4f8fb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00002.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00003.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00003.png
new file mode 100644
index 0000000..cd3ffdb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00003.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00004.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00004.png
new file mode 100644
index 0000000..2285ec7
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00004.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00005.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00005.png
new file mode 100644
index 0000000..8130cb1
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00005.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00006.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00006.png
new file mode 100644
index 0000000..4369a3d
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00006.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00007.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00007.png
new file mode 100644
index 0000000..301e6c7
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00007.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00008.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00008.png
new file mode 100644
index 0000000..442cc82
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00008.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00009.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00009.png
new file mode 100644
index 0000000..78763f6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00009.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00010.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00010.png
new file mode 100644
index 0000000..1ea59a8
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00010.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00011.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00011.png
new file mode 100644
index 0000000..77ea83a
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00011.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00012.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00012.png
new file mode 100644
index 0000000..4e742f5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00012.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00013.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00013.png
new file mode 100644
index 0000000..fa49b62
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00013.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00014.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00014.png
new file mode 100644
index 0000000..dc477a2
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00014.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00015.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00015.png
new file mode 100644
index 0000000..dd85400
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00015.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00000.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00000.png
new file mode 100644
index 0000000..dd85400
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00000.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00001.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00001.png
new file mode 100644
index 0000000..2586aa0
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00001.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00002.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00002.png
new file mode 100644
index 0000000..4022000
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00002.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00003.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00003.png
new file mode 100644
index 0000000..358b428
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00003.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00004.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00004.png
new file mode 100644
index 0000000..1da8c49
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00004.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00005.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00005.png
new file mode 100644
index 0000000..342d6c7
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00005.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00006.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00006.png
new file mode 100644
index 0000000..738bddd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00006.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00007.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00007.png
new file mode 100644
index 0000000..48192c4
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00007.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00008.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00008.png
new file mode 100644
index 0000000..ff1a374
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00008.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00009.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00009.png
new file mode 100644
index 0000000..c13afcd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00009.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00010.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00010.png
new file mode 100644
index 0000000..dde5939
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00010.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00011.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00011.png
new file mode 100644
index 0000000..5c60a08
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00011.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00012.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00012.png
new file mode 100644
index 0000000..5d75964
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00012.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00013.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00013.png
new file mode 100644
index 0000000..cf1c1cd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00013.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00014.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00014.png
new file mode 100644
index 0000000..12ccc03
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00014.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00015.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00015.png
new file mode 100644
index 0000000..16e4cbc
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00015.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_pause_light.png
new file mode 100644
index 0000000..66178aa
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_play_light.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_play_light.png
new file mode 100644
index 0000000..904bbdb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable/ic_collapse.xml b/v7/mediarouter/res/drawable/ic_collapse.xml
new file mode 100644
index 0000000..143e862
--- /dev/null
+++ b/v7/mediarouter/res/drawable/ic_collapse.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="true">
+    <item android:drawable="@drawable/ic_collapse_00000" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00001" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00002" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00003" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00004" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00005" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00006" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00007" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00008" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00009" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00010" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00011" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00012" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00013" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00014" android:duration="13" />
+    <item android:drawable="@drawable/ic_collapse_00015" android:duration="13" />
+</animation-list>
diff --git a/v7/mediarouter/res/drawable/ic_expand.xml b/v7/mediarouter/res/drawable/ic_expand.xml
new file mode 100644
index 0000000..2bd29ae
--- /dev/null
+++ b/v7/mediarouter/res/drawable/ic_expand.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="true">
+    <item android:drawable="@drawable/ic_expand_00000" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00001" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00002" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00003" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00004" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00005" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00006" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00007" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00008" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00009" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00010" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00011" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00012" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00013" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00014" android:duration="13" />
+    <item android:drawable="@drawable/ic_expand_00015" android:duration="13" />
+</animation-list>
diff --git a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml b/v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml
similarity index 67%
rename from v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
rename to v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml
index ec7903b..54f348c 100644
--- a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
+++ b/v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,13 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+
+<!-- This is the copy of @drawable/abc_dialog_material_background_dark except for inset
+     which includes unnecessary padding. -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval" >
-
-    <size
-        android:height="@dimen/lb_guidedactions_item_checkmark_diameter"
-        android:width="@dimen/lb_guidedactions_item_checkmark_diameter" />
-
-    <solid android:color="@color/lb_tv_white" />
-
-</shape>
+        android:shape="rectangle">
+    <corners android:radius="2dp" />
+    <solid android:color="@color/background_floating_material_dark" />
+</shape>
\ No newline at end of file
diff --git a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml b/v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml
similarity index 66%
copy from v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
copy to v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml
index ec7903b..b5d82af 100644
--- a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
+++ b/v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,13 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+
+<!-- This is the copy of @drawable/abc_dialog_material_background_light except for inset
+     which includes unnecessary padding. -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval" >
-
-    <size
-        android:height="@dimen/lb_guidedactions_item_checkmark_diameter"
-        android:width="@dimen/lb_guidedactions_item_checkmark_diameter" />
-
-    <solid android:color="@color/lb_tv_white" />
-
-</shape>
+        android:shape="rectangle">
+    <corners android:radius="2dp" />
+    <solid android:color="@color/background_floating_material_light" />
+</shape>
\ No newline at end of file
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
similarity index 75%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
index a4614f6..05b4a8a 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_setting_light" />
-</selector>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_audiotrack_light"
+    android:alpha="0.87" />
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/mediarouter/res/drawable/mr_ic_close_dark.xml
similarity index 92%
rename from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
rename to v7/mediarouter/res/drawable/mr_ic_close_dark.xml
index a4614f6..4a88cec 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_close_dark.xml
@@ -15,5 +15,5 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_setting_light" />
+    <item android:drawable="@drawable/ic_close_dark" />
 </selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/mediarouter/res/drawable/mr_ic_close_light.xml
similarity index 85%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v7/mediarouter/res/drawable/mr_ic_close_light.xml
index a4614f6..c663ae8 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_close_light.xml
@@ -15,5 +15,10 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_setting_light" />
+    <item>
+        <bitmap
+            android:src="@drawable/ic_close_light"
+            android:alpha="0.87" />
+    </item>
+
 </selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_pause_light.xml b/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
index 9702be8..0cea425 100644
--- a/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
@@ -15,5 +15,9 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_pause_light" />
+    <item>
+        <bitmap
+            android:src="@drawable/ic_pause_light"
+            android:alpha="0.87" />
+    </item>
 </selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_play_light.xml b/v7/mediarouter/res/drawable/mr_ic_play_light.xml
index d18cc12..48a7e03 100644
--- a/v7/mediarouter/res/drawable/mr_ic_play_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_play_light.xml
@@ -15,5 +15,9 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_play_light" />
+    <item>
+        <bitmap
+            android:src="@drawable/ic_play_light"
+            android:alpha="0.87" />
+    </item>
 </selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_dark.xml b/v7/mediarouter/res/drawable/mr_ic_settings_dark.xml
deleted file mode 100644
index 0fe662e..0000000
--- a/v7/mediarouter/res/drawable/mr_ic_settings_dark.xml
+++ /dev/null
@@ -1,19 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_setting_dark" />
-</selector>
diff --git a/v17/preference-leanback/res/values/ids.xml b/v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml
similarity index 77%
copy from v17/preference-leanback/res/values/ids.xml
copy to v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml
index 20c1eda..a51bfce 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml
@@ -15,6 +15,8 @@
   ~ limitations under the License
   -->
 
-<resources>
-    <item name="transitionPosition" type="id" />
-</resources>
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:controlX1="0.4"
+    android:controlY1="0"
+    android:controlX2="0.2"
+    android:controlY2="1"/>
diff --git a/v17/preference-leanback/res/values/ids.xml b/v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml
similarity index 77%
copy from v17/preference-leanback/res/values/ids.xml
copy to v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml
index 20c1eda..d500c8b 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml
@@ -15,6 +15,8 @@
   ~ limitations under the License
   -->
 
-<resources>
-    <item name="transitionPosition" type="id" />
-</resources>
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:controlX1="0"
+    android:controlY1="0"
+    android:controlX2="0.2"
+    android:controlY2="1"/>
diff --git a/v7/mediarouter/res/layout-v17/mr_media_route_list_item.xml b/v7/mediarouter/res/layout-v17/mr_media_route_list_item.xml
deleted file mode 100644
index 1b798ee..0000000
--- a/v7/mediarouter/res/layout-v17/mr_media_route_list_item.xml
+++ /dev/null
@@ -1,48 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="?android:attr/listPreferredItemHeight"
-              android:gravity="center_vertical">
-
-    <LinearLayout android:layout_width="0dp"
-                  android:layout_height="match_parent"
-                  android:layout_weight="1"
-                  android:orientation="vertical"
-                  android:gravity="start|center_vertical"
-                  android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-                  android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-                  android:duplicateParentState="true">
-
-        <TextView android:id="@android:id/text1"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:ellipsize="marquee"
-                  android:textAppearance="?android:attr/textAppearanceMedium"
-                  android:duplicateParentState="true" />
-
-        <TextView android:id="@android:id/text2"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:ellipsize="marquee"
-                  android:textAppearance="?android:attr/textAppearanceSmall"
-                  android:duplicateParentState="true" />
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_media_route_chooser_dialog.xml b/v7/mediarouter/res/layout/mr_chooser_dialog.xml
similarity index 61%
rename from v7/mediarouter/res/layout/mr_media_route_chooser_dialog.xml
rename to v7/mediarouter/res/layout/mr_chooser_dialog.xml
index afdad71..bda99f5 100644
--- a/v7/mediarouter/res/layout/mr_media_route_chooser_dialog.xml
+++ b/v7/mediarouter/res/layout/mr_chooser_dialog.xml
@@ -14,28 +14,32 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="fill_parent"
+             android:layout_height="wrap_content" >
+
+    <ListView android:id="@+id/mr_chooser_list"
               android:layout_width="fill_parent"
               android:layout_height="wrap_content"
-              android:orientation="vertical">
-    <ListView android:id="@+id/media_route_list"
-              android:layout_width="fill_parent"
-              android:layout_height="wrap_content" />
+              android:divider="@android:color/transparent"
+              android:dividerHeight="0dp" />
 
     <LinearLayout android:id="@android:id/empty"
               android:layout_width="fill_parent"
-              android:layout_height="64dp"
-              android:orientation="horizontal"
+              android:layout_height="240dp"
+              android:orientation="vertical"
+              android:paddingTop="90dp"
               android:paddingLeft="16dp"
               android:paddingRight="16dp"
               android:visibility="gone">
-        <ProgressBar android:layout_width="wrap_content"
-                     android:layout_height="wrap_content"
-                     android:layout_gravity="center" />
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_gravity="center"
-                  android:paddingLeft="16dp"
-                  android:text="@string/mr_media_route_chooser_searching" />
+                  android:text="@string/mr_chooser_searching" />
+        <ProgressBar android:layout_width="150dp"
+                     android:layout_height="wrap_content"
+                     android:layout_gravity="center"
+                     android:indeterminate="true"
+                     style="?android:attr/progressBarStyleHorizontal" />
     </LinearLayout>
-</LinearLayout>
+</FrameLayout>
diff --git a/v7/mediarouter/res/layout/mr_chooser_list_item.xml b/v7/mediarouter/res/layout/mr_chooser_list_item.xml
new file mode 100644
index 0000000..d578560
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_chooser_list_item.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              android:minHeight="56dp"
+              android:paddingLeft="24dp"
+              android:paddingRight="24dp"
+              android:orientation="horizontal"
+              android:gravity="center_vertical" >
+
+    <ImageView android:id="@+id/mr_chooser_route_icon"
+               android:layout_width="24dp"
+               android:layout_height="24dp"
+               android:layout_marginRight="24dp" />
+
+    <LinearLayout android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_marginBottom="1dp"
+                  android:orientation="vertical" >
+
+        <TextView android:id="@+id/mr_chooser_route_name"
+                  android:layout_width="fill_parent"
+                  android:layout_height="32dp"
+                  android:singleLine="true"
+                  android:ellipsize="marquee"
+                  android:textAppearance="?attr/mediaRouteChooserPrimaryTextStyle" />
+
+        <TextView android:id="@+id/mr_chooser_route_desc"
+                  android:layout_width="fill_parent"
+                  android:layout_height="24dp"
+                  android:singleLine="true"
+                  android:ellipsize="marquee"
+                  android:textAppearance="?attr/mediaRouteChooserSecondaryTextStyle" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml b/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
new file mode 100644
index 0000000..091f5f8
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
@@ -0,0 +1,96 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+          android:id="@+id/mr_expandable_area"
+          android:background="@android:color/transparent"
+          android:layout_width="fill_parent"
+          android:layout_height="fill_parent">
+    <LinearLayout android:id="@+id/mr_dialog_area"
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:background="?attr/MediaRouteControllerWindowBackground"
+                  android:layout_gravity="center"
+                  android:orientation="vertical">
+        <LinearLayout android:id="@+id/mr_title_bar"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:paddingLeft="24dp"
+                      android:paddingRight="12dp"
+                      android:orientation="horizontal" >
+            <TextView android:id="@+id/mr_name"
+                      android:layout_width="0dp"
+                      android:layout_height="72dp"
+                      android:layout_weight="1"
+                      android:gravity="center_vertical"
+                      android:singleLine="true"
+                      android:ellipsize="end"
+                      android:textAppearance="?attr/mediaRouteControllerTitleTextStyle" />
+            <ImageButton android:id="@+id/mr_close"
+                         android:layout_width="48dp"
+                         android:layout_height="48dp"
+                         android:layout_gravity="center_vertical"
+                         android:contentDescription="@string/mr_controller_close_description"
+                         android:src="?attr/mediaRouteCloseDrawable"
+                         android:background="?attr/selectableItemBackgroundBorderless" />
+        </LinearLayout>
+        <FrameLayout android:id="@+id/mr_custom_control"
+                     android:layout_width="fill_parent"
+                     android:layout_height="wrap_content"
+                     android:visibility="gone" />
+        <FrameLayout android:id="@+id/mr_default_control"
+                     android:layout_width="fill_parent"
+                     android:layout_height="wrap_content">
+            <ImageView android:id="@+id/mr_art"
+                       android:layout_width="fill_parent"
+                       android:layout_height="wrap_content"
+                       android:adjustViewBounds="true"
+                       android:scaleType="fitXY"
+                       android:background="?attr/colorPrimary"
+                       android:layout_gravity="top"
+                       android:visibility="gone" />
+            <LinearLayout android:layout_width="fill_parent"
+                          android:layout_height="wrap_content"
+                          android:orientation="vertical"
+                          android:layout_gravity="bottom">
+                <LinearLayout android:id="@+id/mr_media_main_control"
+                              android:layout_width="fill_parent"
+                              android:layout_height="wrap_content"
+                              android:orientation="vertical"
+                              android:paddingTop="16dp"
+                              android:paddingBottom="16dp"
+                              android:layout_gravity="bottom">
+                    <include android:id="@+id/mr_playback_control"
+                             layout="@layout/mr_playback_control" />
+                    <View android:id="@+id/mr_control_divider"
+                          android:layout_width="fill_parent"
+                          android:layout_height="8dp"
+                          android:visibility="gone" />
+                    <include android:id="@+id/mr_volume_control"
+                             layout="@layout/mr_volume_control" />
+                </LinearLayout>
+                <ListView android:id="@+id/mr_volume_group_list"
+                          android:layout_width="fill_parent"
+                          android:layout_height="wrap_content"
+                          android:paddingTop="@dimen/mr_controller_volume_group_list_padding_top"
+                          android:scrollbarStyle="outsideOverlay"
+                          android:clipToPadding="false"
+                          android:visibility="gone" />
+            </LinearLayout>
+        </FrameLayout>
+        <include layout="@layout/abc_alert_dialog_button_bar_material" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/v7/mediarouter/res/layout/mr_controller_volume_item.xml b/v7/mediarouter/res/layout/mr_controller_volume_item.xml
new file mode 100644
index 0000000..4d693e2
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_controller_volume_item.xml
@@ -0,0 +1,46 @@
+<?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:layout_width="fill_parent"
+              android:layout_height="@dimen/mr_controller_volume_group_list_item_height"
+              android:paddingLeft="24dp"
+              android:paddingRight="60dp"
+              android:paddingBottom="8dp"
+              android:orientation="vertical" >
+    <TextView android:id="@+id/mr_name"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:textAppearance="?attr/mediaRouteControllerSecondaryTextStyle"
+              android:singleLine="true" />
+    <LinearLayout android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal"
+                  android:gravity="center_vertical">
+        <ImageView android:id="@+id/mr_volume_item_icon"
+                   android:layout_width="@dimen/mr_controller_volume_group_list_item_icon_size"
+                   android:layout_height="@dimen/mr_controller_volume_group_list_item_icon_size"
+                   android:layout_marginTop="8dp"
+                   android:layout_marginBottom="8dp"
+                   android:scaleType="fitCenter"
+                   android:src="?attr/mediaRouteAudioTrackDrawable" />
+        <android.support.v7.app.MediaRouteVolumeSlider android:id="@+id/mr_volume_slider"
+                 android:layout_width="fill_parent"
+                 android:layout_height="40dp"
+                 android:minHeight="40dp"
+                 android:maxHeight="40dp" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml b/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
deleted file mode 100644
index 3e5f7d9..0000000
--- a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
+++ /dev/null
@@ -1,141 +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.
--->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-    <LinearLayout android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical">
-        <LinearLayout android:id="@+id/title_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-            <TextView android:id="@+id/route_name"
-                    android:layout_width="0dp"
-                    android:layout_height="72dp"
-                    android:layout_weight="1"
-                    android:layout_marginLeft="24dip"
-                    android:layout_marginRight="24dip"
-                    android:gravity="center_vertical"
-                    android:singleLine="true"
-                    android:ellipsize="end"
-                    android:textAppearance="?android:attr/textAppearanceMedium"
-                    android:textColor="?android:attr/textColorPrimary" />
-            <ImageButton android:id="@+id/settings"
-                    android:layout_width="48dip"
-                    android:layout_height="48dip"
-                    android:padding="12dip"
-                    android:layout_marginTop="12dip"
-                    android:layout_marginBottom="12dip"
-                    android:layout_marginRight="12dip"
-                    android:contentDescription="@string/mr_media_route_controller_settings_description"
-                    android:src="?attr/mediaRouteSettingsDrawable"
-                    android:background="?attr/selectableItemBackgroundBorderless"
-                    android:visibility="gone" />
-        </LinearLayout>
-        <FrameLayout android:id="@+id/media_route_control_frame"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" >
-            <RelativeLayout android:id="@+id/default_control_frame"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:background="?attr/colorPrimary" >
-                <ImageView android:id="@+id/art"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:maxHeight="@dimen/mr_media_route_controller_art_max_height"
-                        android:adjustViewBounds="true"
-                        android:scaleType="centerCrop"/>
-                <ImageButton android:id="@+id/play_pause"
-                        android:layout_width="48dip"
-                        android:layout_height="48dip"
-                        android:padding="12dip"
-                        android:layout_marginTop="8dip"
-                        android:layout_marginBottom="8dip"
-                        android:layout_alignParentRight="true"
-                        android:layout_below="@id/art"
-                        android:contentDescription="@string/mr_media_route_controller_play"
-                        android:background="?attr/selectableItemBackgroundBorderless"/>
-                <LinearLayout android:orientation="vertical"
-                        android:layout_height="wrap_content"
-                        android:layout_width="wrap_content"
-                        android:minHeight="64dip"
-                        android:layout_marginLeft="24dip"
-                        android:gravity="center_vertical"
-                        android:layout_toLeftOf="@id/play_pause"
-                        android:layout_below="@id/art"
-                        android:layout_alignParentLeft="true" >
-                    <TextView android:id="@+id/title"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:textAppearance="?android:attr/textAppearanceSmall"
-                            android:textColor="?android:attr/textColorPrimary"
-                            android:textSize="16sp"
-                            android:textStyle="bold"
-                            android:singleLine="true" />
-                    <TextView android:id="@+id/subtitle"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:textAppearance="?android:attr/textAppearanceSmall"
-                            android:textColor="?android:attr/textColorPrimary"
-                            android:textSize="14sp"
-                            android:singleLine="true" />
-                </LinearLayout>
-            </RelativeLayout>
-        </FrameLayout>
-        <!-- Optional volume slider section. -->
-        <LinearLayout android:id="@+id/media_route_volume_layout"
-                      android:layout_width="fill_parent"
-                      android:layout_height="64dp"
-                      android:gravity="center_vertical"
-                      android:padding="8dp"
-                      android:visibility="gone">
-            <ImageView android:layout_width="48dp"
-                       android:layout_height="48dp"
-                       android:src="?attr/mediaRouteCastDrawable"
-                       android:gravity="center"
-                       android:scaleType="center" />
-            <SeekBar android:id="@+id/media_route_volume_slider"
-                     android:layout_width="0dp"
-                     android:layout_height="wrap_content"
-                     android:layout_weight="1"
-                     android:layout_marginLeft="8dp"
-                     android:layout_marginRight="8dp" />
-        </LinearLayout>
-        <LinearLayout android:id="@+id/buttons"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-            <Button android:id="@+id/disconnect"
-                android:layout_width="0dp"
-                android:layout_height="48dp"
-                android:gravity="center"
-                android:layout_weight="1"
-                android:background="?attr/selectableItemBackgroundBorderless"
-                android:text="@string/mr_media_route_controller_disconnect"
-                android:visibility="gone" />
-            <Button android:id="@+id/stop"
-                android:layout_width="0dp"
-                android:layout_height="48dp"
-                android:gravity="center"
-                android:layout_weight="1"
-                android:textColor="?attr/colorAccent"
-                android:background="?attr/selectableItemBackgroundBorderless"
-                android:text="@string/mr_media_route_controller_stop" />
-        </LinearLayout>
-    </LinearLayout>
-</ScrollView>
diff --git a/v7/mediarouter/res/layout/mr_media_route_list_item.xml b/v7/mediarouter/res/layout/mr_media_route_list_item.xml
deleted file mode 100644
index 6c63a12..0000000
--- a/v7/mediarouter/res/layout/mr_media_route_list_item.xml
+++ /dev/null
@@ -1,48 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="fill_parent"
-              android:layout_height="64dp"
-              android:gravity="center_vertical">
-
-    <LinearLayout android:layout_width="0dp"
-                  android:layout_height="fill_parent"
-                  android:layout_weight="1"
-                  android:orientation="vertical"
-                  android:gravity="left|center_vertical"
-                  android:paddingLeft="16dp"
-                  android:paddingRight="16dp"
-                  android:duplicateParentState="true">
-
-        <TextView android:id="@android:id/text1"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:ellipsize="marquee"
-                  android:textAppearance="?android:attr/textAppearanceMedium"
-                  android:duplicateParentState="true" />
-
-        <TextView android:id="@android:id/text2"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:ellipsize="marquee"
-                  android:textAppearance="?android:attr/textAppearanceSmall"
-                  android:duplicateParentState="true" />
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_playback_control.xml b/v7/mediarouter/res/layout/mr_playback_control.xml
new file mode 100644
index 0000000..9ee2191
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_playback_control.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:paddingLeft="24dp"
+                android:paddingRight="12dp" >
+    <ImageButton android:id="@+id/mr_control_play_pause"
+                 android:layout_width="wrap_content"
+                 android:layout_height="wrap_content"
+                 android:layout_marginLeft="12dp"
+                 android:layout_alignParentRight="true"
+                 android:layout_centerVertical="true"
+                 android:contentDescription="@string/mr_controller_play"
+                 android:background="?attr/selectableItemBackgroundBorderless"
+                 android:visibility="gone" />
+    <LinearLayout android:id="@+id/mr_control_title_container"
+                  android:orientation="vertical"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_toLeftOf="@id/mr_control_play_pause"
+                  android:layout_alignParentLeft="true"
+                  android:layout_centerVertical="true">
+        <TextView android:id="@+id/mr_control_title"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:textAppearance="?attr/mediaRouteControllerPrimaryTextStyle"
+                  android:singleLine="true" />
+        <TextView android:id="@+id/mr_control_subtitle"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:textAppearance="?attr/mediaRouteControllerSecondaryTextStyle"
+                  android:singleLine="true" />
+    </LinearLayout>
+</RelativeLayout>
diff --git a/v7/mediarouter/res/layout/mr_volume_control.xml b/v7/mediarouter/res/layout/mr_volume_control.xml
new file mode 100644
index 0000000..f22cbf6
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_volume_control.xml
@@ -0,0 +1,48 @@
+<?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:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp"
+        android:gravity="center_vertical"
+        android:paddingLeft="24dp"
+        android:paddingRight="12dp">
+    <ImageView
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="?attr/mediaRouteAudioTrackDrawable"
+            android:gravity="center"
+            android:scaleType="center"/>
+    <!-- Since dialog's top layout mr_expandable_area is clickable, it propagates pressed state
+         to its non-clickable children. Specify android:clickable="true" to prevent volume slider
+         from having false pressed state. -->
+    <android.support.v7.app.MediaRouteVolumeSlider
+            android:id="@+id/mr_volume_slider"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:minHeight="48dp"
+            android:maxHeight="48dp"
+            android:layout_weight="1"
+            android:clickable="true" />
+    <android.support.v7.app.MediaRouteExpandCollapseButton
+            android:id="@+id/mr_group_expand_collapse"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:padding="12dp"
+            android:background="?attr/selectableItemBackgroundBorderless"
+            android:visibility="gone"/>
+</LinearLayout>
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
index 8f44f51..024a99c 100644
--- a/v7/mediarouter/res/values-af/strings.xml
+++ b/v7/mediarouter/res/values-af/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Stelsel"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Toestelle"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Saai uit"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Koppel aan toestel"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Soek tans vir toestelle…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ontkoppel"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Hou op uitsaai"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Roete-instellings"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Speel"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Laat wag"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Geen inligting beskikbaar nie"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knoppie"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Hou op uitsaai"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Maak toe"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Speel"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Laat wag"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
index ec3fa64..4456b45 100644
--- a/v7/mediarouter/res/values-am/strings.xml
+++ b/v7/mediarouter/res/values-am/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"ስርዓት"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"መሣሪያዎች"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ውሰድ"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ከመሳሪያ ጋር ያገናኙ"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"መሳሪያዎችን በመፈለግ ላይ…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ግንኙነት አቋርጥ"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"መውሰድ አቁም"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"የመንገድ ቅንብሮች"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"አጫውት"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ለአፍታ አቁም"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ምንም መረጃ አይገኝም"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"የ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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Cast ማድረግ አቁም"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"ዝጋ"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"አጫውት"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"ለአፍታ አቁም"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"አስፋ"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ሰብስብ"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
index 078a9bf..7222590 100644
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ b/v7/mediarouter/res/values-ar/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"إرسال"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"الاتصال بجهاز"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"جارٍ البحث عن الأجهزة…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"قطع الاتصال"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"إيقاف الإرسال"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"إعدادات المسار"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"تشغيل"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"إيقاف مؤقت"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"لا تتوفر أية معلومات"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"زر الإرسال"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"إيقاف الإرسال"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"إغلاق"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"تشغيل"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"إيقاف مؤقت"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"توسيع"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"تصغير"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-az-rAZ/strings.xml b/v7/mediarouter/res/values-az-rAZ/strings.xml
index 27b4a91..aa3a70f 100644
--- a/v7/mediarouter/res/values-az-rAZ/strings.xml
+++ b/v7/mediarouter/res/values-az-rAZ/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"İştirakçılar"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Cihaza qoş"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Cihazları axtarır..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Bağlantını kəs"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Yayımı dayandır"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Marşrut parametrləri"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Göstər"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Fasilə ver"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Əlçatan info yoxdur"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Yayım düyməsi"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Yayımı dayandırın"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Qapadın"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Oynadın"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Durdurun"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
index 90e3b53..de49179 100644
--- a/v7/mediarouter/res/values-bg/strings.xml
+++ b/v7/mediarouter/res/values-bg/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Предаване"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Свързване с устройство"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Търсят се устройства…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Прекратяване на връзката"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Спиране на предаването"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Настройки за маршрута"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Пускане"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Поставяне на пауза"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Няма налична информация"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Бутон за предаване"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Спиране на предаването"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Затваряне"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Пускане"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Поставяне на пауза"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгъване"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свиване"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-bn-rBD/strings.xml b/v7/mediarouter/res/values-bn-rBD/strings.xml
index 5382752..7eb5301 100644
--- a/v7/mediarouter/res/values-bn-rBD/strings.xml
+++ b/v7/mediarouter/res/values-bn-rBD/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"সিস্টেম"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ডিভাইসগুলি"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"কাস্ট করুন"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ডিভাইসে সংযোগ করুন"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ডিভাইসগুলি অনুসন্ধান করা হচ্ছে…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"সংযোগ বিচ্ছিন্ন করুন"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"কাস্ট করা বন্ধ করুন"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"সেটিংস রুট করুন"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"চালান"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"বিরাম দিন"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"কোনো তথ্য উপলব্ধ নেই"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"কাস্ট করার বোতাম"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"কাস্ট করা বন্ধ করুন"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"বন্ধ করুন"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"চালান"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"বিরাম দিন"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"প্রসারিত করুন"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"সঙ্কুচিত করুন"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
index c3b9bd5..ab8809a 100644
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ b/v7/mediarouter/res/values-ca/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Emet"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connecta al dispositiu"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"S\'estan cercant dispositius…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconnecta"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Atura l\'emissió"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuració de la ruta"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reprodueix"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Posa en pausa"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No hi ha informació disponible"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botó d\'emetre"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Atura l\'emissió"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tanca"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reprodueix"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Posa en pausa"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Desplega"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Replega"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/res/values-cs/strings.xml
index e85c3e2..57c1594 100644
--- a/v7/mediarouter/res/values-cs/strings.xml
+++ b/v7/mediarouter/res/values-cs/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Odeslat"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Připojení k zařízení"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Vyhledávání zařízení…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Odpojit"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ukončit odesílání"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavení trasy"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Přehrát"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pozastavit"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Žádné informace"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačítko odesílání"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Zastavit odesílání"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zavřít"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Přehrát"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pozastavit"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbalit"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sbalit"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
index c0f2322..eb6c8fa 100644
--- a/v7/mediarouter/res/values-da/strings.xml
+++ b/v7/mediarouter/res/values-da/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Opret forbindelse til enheden"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Søger efter enheder..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Afbryd forbindelsen"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop med at caste"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ruteindstillinger"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Afspil"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sæt på pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Der er ingen tilgængelige oplysninger"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knap"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Stop med at caste"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Luk"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Afspil"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Sæt på pause"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Udvid"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/res/values-de/strings.xml
index 22b3e1a..17a84af 100644
--- a/v7/mediarouter/res/values-de/strings.xml
+++ b/v7/mediarouter/res/values-de/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Übertragen"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Mit Gerät verbinden"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Geräte werden gesucht…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Verbindung aufheben"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Übertragung stoppen"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Routingeinstellungen"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Wiedergabe"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Keine Informationen verfügbar"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-Symbol"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Streaming stoppen"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Schließen"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Wiedergeben"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausieren"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Maximieren"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minimieren"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
index 5b4fff1..9258296 100644
--- a/v7/mediarouter/res/values-el/strings.xml
+++ b/v7/mediarouter/res/values-el/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Σύστημα"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Συσκευές"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Μετάδοση"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Σύνδεση με τη συσκευή"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Αναζήτηση συσκευών…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Αποσύνδεση"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Διακοπή μετάδοσης"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ρυθμίσεις διαδρομής"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Αναπαραγωγή"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Παύση"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Δεν υπάρχουν διαθέσιμες πληροφορίες"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Κουμπί 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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Διακοπή μετάδοσης"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Κλείσιμο"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Αναπαραγωγή"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Παύση"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ανάπτυξη"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Σύμπτυξη"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
index 21f25a9..5edd79b 100644
--- a/v7/mediarouter/res/values-en-rAU/strings.xml
+++ b/v7/mediarouter/res/values-en-rAU/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No info available"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Stop casting"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
index 21f25a9..5edd79b 100644
--- a/v7/mediarouter/res/values-en-rGB/strings.xml
+++ b/v7/mediarouter/res/values-en-rGB/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No info available"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Stop casting"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
index 21f25a9..5edd79b 100644
--- a/v7/mediarouter/res/values-en-rIN/strings.xml
+++ b/v7/mediarouter/res/values-en-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No info available"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Stop casting"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
index e9f1707..b0a0a61 100644
--- a/v7/mediarouter/res/values-es-rUS/strings.xml
+++ b/v7/mediarouter/res/values-es-rUS/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar al dispositivo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Detener transmisión"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuración de ruta"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproducir"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No hay información disponible"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botón para transmitir"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Detener la transmisión"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Cerrar"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reproducir"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
index 44aa935..3a1eaeb 100644
--- a/v7/mediarouter/res/values-es/strings.xml
+++ b/v7/mediarouter/res/values-es/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Enviar contenido"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar a dispositivo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Dejar de enviar contenido"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ajustes de ruta"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproducir"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No hay información disponible"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de enviar"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Dejar de enviar contenido"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Cerrar"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reproducir"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-et-rEE/strings.xml b/v7/mediarouter/res/values-et-rEE/strings.xml
index d0a4263..9058dcf 100644
--- a/v7/mediarouter/res/values-et-rEE/strings.xml
+++ b/v7/mediarouter/res/values-et-rEE/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Ülekandmine"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Seadmega ühendamine"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Seadmete otsimine …"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Katkesta ühendus"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Lõpeta ülekanne"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Marsruudi seaded"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Esitamine"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Peatamine"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Teave pole saadaval"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Ülekandenupp"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Peata ülekanne"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Sulgemine"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Esitamine"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Peatamine"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laiendamine"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ahendamine"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-eu-rES/strings.xml b/v7/mediarouter/res/values-eu-rES/strings.xml
index 463a56d..ad85c5a 100644
--- a/v7/mediarouter/res/values-eu-rES/strings.xml
+++ b/v7/mediarouter/res/values-eu-rES/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Igorri"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Konektatu gailura"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Gailuak bilatzen…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Deskonektatu"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Utzi igortzeari"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ibilbidearen ezarpenak"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Erreproduzitu"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausatu"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Ez dago informaziorik"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Igorri botoia"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Utzi igortzeari"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Itxi"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Erreproduzitu"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausatu"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zabaldu"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tolestu"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
index 191fc832..87a81ba 100644
--- a/v7/mediarouter/res/values-fa/strings.xml
+++ b/v7/mediarouter/res/values-fa/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"سیستم"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"دستگاه‌ها"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"فرستادن"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"برقراری ارتباط با دستگاه"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"در حال جستجو برای دستگاه‌ها..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"قطع ارتباط"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"توقف فرستادن"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"تنظیمات مسیر"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"پخش"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"مکث"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"اطلاعات دردسترس نیست"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"دکمه ارسال محتوا"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"توقف ارسال محتوا"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"بستن"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"پخش"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"توقف موقت"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"بزرگ کردن"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"کوچک کردن"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
index b5960ab..a93d74e 100644
--- a/v7/mediarouter/res/values-fi/strings.xml
+++ b/v7/mediarouter/res/values-fi/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Lähetä"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Yhdistä laitteeseen"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Etsitään laitteita…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Katkaise yhteys"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Lopeta suoratoisto"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Reitin asetukset"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Toista"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Keskeytä"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Tietoja ei ole saatavilla"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-painike"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Lopeta suoratoisto"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Sulje"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Toista"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Keskeytä"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laajenna"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tiivistä"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
index 799cc7e..f0c6976 100644
--- a/v7/mediarouter/res/values-fr-rCA/strings.xml
+++ b/v7/mediarouter/res/values-fr-rCA/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Diffuser"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connexion au périphérique"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Recherche d\'appareils en cours…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Déconnecter"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Arrêter la diffusion"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Paramètres de l\'itinéraire"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Lecture"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Suspendre"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Aucune information disponible"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Bouton Diffuser"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Arrêter la diffusion"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fermer"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Lire"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Interrompre"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
index fec6833..de94f18 100644
--- a/v7/mediarouter/res/values-fr/strings.xml
+++ b/v7/mediarouter/res/values-fr/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Caster"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connecter à l\'appareil"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Recherche d\'appareils en cours…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Déconnecter"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Arrêter la diffusion"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Paramètres de l\'itinéraire"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Lecture"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Aucune information disponible"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Icône Cast"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"Diffuser 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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Arrêter de diffuser"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fermer"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Lecture"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl-rES/strings.xml
index 56ce29c..fb76c68 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl-rES/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Emitir"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar co dispositivo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Parar de emitir"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuración da ruta"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduce"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Non hai información dispoñible"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de emitir"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Parar de emitir"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Pechar"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reproduce"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ampliar"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Contraer"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-gu-rIN/strings.xml b/v7/mediarouter/res/values-gu-rIN/strings.xml
index 3d1c36e3..211f836 100644
--- a/v7/mediarouter/res/values-gu-rIN/strings.xml
+++ b/v7/mediarouter/res/values-gu-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"સિસ્ટમ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ઉપકરણો"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"કાસ્ટ કરો"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ઉપકરણ સાથે કનેક્ટ કરો"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ઉપકરણો માટે શોધી રહ્યું છે…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ડિસ્કનેક્ટ કરો"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"કાસ્ટ કરવાનું રોકો"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"રૂટ સેટિંગ્સ"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ચલાવો"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"થોભો"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"કોઈ માહિતી ઉપલબ્ધ નથી"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"કાસ્ટ કરો બટન"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"કાસ્ટ કરવાનું રોકો"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"બંધ કરો"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ચલાવો"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"થોભાવો"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"વિસ્તૃત કરો"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"સંકુચિત કરો"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index d1fa0ba..e2c7a43 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिवाइस"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट करें"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"डिवाइस से कनेक्ट करें"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"डिवाइस की खोज हो रही है…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"डिस्कनेक्ट करें"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्ट करना बंद करें"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिंग"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"चलाएं"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"रोकें"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"कोई जानकारी उपलब्‍ध नहीं"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट करें बटन"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"कास्ट करना बंद करें"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"बंद करें"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"चलाएं"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"रोकें"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करें"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त करें"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
index 7030acc..d79258fbf 100644
--- a/v7/mediarouter/res/values-hr/strings.xml
+++ b/v7/mediarouter/res/values-hr/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Emitiranje"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Povezivanje s uređajem"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Traženje uređaja…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Prekini vezu"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zaustavi emitiranje"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Postavke rute"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reprodukcija"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pauziraj"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Informacije nisu dostupne"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za emitiranje"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Zaustavi emitiranje"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zatvaranje"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reprodukcija"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pauziranje"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
index 25c2518..7686fea 100644
--- a/v7/mediarouter/res/values-hu/strings.xml
+++ b/v7/mediarouter/res/values-hu/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Tartalomátküldés"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Csatlakozás adott eszközhöz"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Eszközkeresés…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Leválasztás"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Átküldés leállítása"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Útvonal-beállítások"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Indítás"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Szüneteltetés"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nincs információ"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Átküldés gomb"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Átküldés leállítása"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Bezárás"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Lejátszás"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Szüneteltetés"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-hy-rAM/strings.xml b/v7/mediarouter/res/values-hy-rAM/strings.xml
index ac02c1a..85bd488 100644
--- a/v7/mediarouter/res/values-hy-rAM/strings.xml
+++ b/v7/mediarouter/res/values-hy-rAM/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Համակարգ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Սարքեր"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Հեռարձակում"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Միանալ սարքին"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Որոնվում են սարքեր..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Անջատել"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Դադարեցնել հեռարձակումը"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ֆայլերի փոխանցման կարգավորումներ"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Նվագարկել"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Դադար"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Տեղեկությունները հասանելի չեն"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Հեռարձակման կոճակ"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Դադարեցնել հեռարձակումը"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Փակել"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Նվագարկել"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Դադար"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ընդարձակել"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Կոծկել"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index 96e08b5..3d01880 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmisi"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Sambungkan ke perangkat"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Menelusuri perangkat…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Putuskan sambungan"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Hentikan transmisi"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Setelan rute"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Putar"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Jeda"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Tidak ada info yang tersedia"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Tombol transmisi"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"Transmisi ke"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Hentikan transmisi"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Putar"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-is-rIS/strings.xml b/v7/mediarouter/res/values-is-rIS/strings.xml
index 66d5ca5..366f6f6 100644
--- a/v7/mediarouter/res/values-is-rIS/strings.xml
+++ b/v7/mediarouter/res/values-is-rIS/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Senda út"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Tengjast tæki"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Leitar að tækjum…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Aftengja"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stöðva útsendingu"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Leiðarstillingar"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spila"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Hlé"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Engar upplýsingar í boði"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Útsendingarhnappur"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Stöðva útsendingu"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Loka"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Spila"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Hlé"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
index c04f408..9febd99 100644
--- a/v7/mediarouter/res/values-it/strings.xml
+++ b/v7/mediarouter/res/values-it/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivi"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Trasmetti"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connetti al dispositivo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Ricerca di dispositivi…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnetti"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interrompi trasmissione"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Impostazioni percorso"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Riproduci"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nessuna informazione disponibile"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Pulsante Trasmetti"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Interrompi trasmissione"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Chiudi"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Riproduci"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Espandi"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Comprimi"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
index 60fdc53..d1698a5 100644
--- a/v7/mediarouter/res/values-iw/strings.xml
+++ b/v7/mediarouter/res/values-iw/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"מערכת"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"מכשירים"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"העבר"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"התחבר למכשיר"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"מחפש מכשירים…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"התנתק"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"עצור העברה"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"הגדרות נתיב"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"הפעל"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"השהה"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"אין מידע זמין"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"‏לחצן הפעלת 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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"עצור העברה"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"סגור"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"הפעל"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"השהה"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"הרחב"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"כווץ"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
index 0b39a09..ea8d838 100644
--- a/v7/mediarouter/res/values-ja/strings.xml
+++ b/v7/mediarouter/res/values-ja/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"システム"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"端末"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"キャスト"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"端末に接続"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"端末を検索しています…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"接続を解除"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"キャストを停止"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ルーティング設定"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"再生"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"一時停止"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"情報がありません"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"キャストアイコン"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"キャストを停止"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"閉じる"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"再生"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"一時停止"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折りたたむ"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ka-rGE/strings.xml b/v7/mediarouter/res/values-ka-rGE/strings.xml
index 9f0761b..2182b64 100644
--- a/v7/mediarouter/res/values-ka-rGE/strings.xml
+++ b/v7/mediarouter/res/values-ka-rGE/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"სისტემა"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"მოწყობილობები"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"მსახიობები"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"მოწყობილობასთან დაკავშირება"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"მოწყობილობების ძიება…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"კავშირის გაწყვეტა"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ტრანსლაციის შეჩერება"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"მარშრუტის პარამეტრები"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"დაკვრა"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"პაუზა"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ინფორმაცია არ არის ხელმისაწვდომი"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ტრანსლირების ღილაკი"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"ტრანსლირების შეჩერება"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"დახურვა"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"დაკვრა"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"პაუზა"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"გაშლა"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ჩაკეცვა"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-kk-rKZ/strings.xml b/v7/mediarouter/res/values-kk-rKZ/strings.xml
index 2fea3dd..5c72c5f 100644
--- a/v7/mediarouter/res/values-kk-rKZ/strings.xml
+++ b/v7/mediarouter/res/values-kk-rKZ/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Жүйе"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Құрылғылар"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Трансляциялау"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Құрылғыға жалғау"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Құрылғыларды іздеуде…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ажырату"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Трансляциялауды тоқтату"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Жол параметрлері"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ойнату"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Кідірту"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Қолжетімді ақпарат жоқ"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Трансляциялау түймесі"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Трансляциялауды тоқтату"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Жабу"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Ойнату"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Кідірту"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жаю"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жию"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-km-rKH/strings.xml b/v7/mediarouter/res/values-km-rKH/strings.xml
index 0a62013..cdf94db 100644
--- a/v7/mediarouter/res/values-km-rKH/strings.xml
+++ b/v7/mediarouter/res/values-km-rKH/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"ប្រព័ន្ធ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ឧបករណ៍"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"បញ្ជូន"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ភ្ជាប់​ឧបករណ៍"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"កំពុង​ស្វែងរក​ឧបករណ៍..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ផ្ដាច់"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"បញ្ឈប់ការខាស"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ការកំណត់ផ្លូវ"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ចាក់"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ផ្អាក"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"មិនមានព័ត៌មានទេ"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ប៊ូតុងខាស"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"បញ្ឈប់ការខាស"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"បិទ"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ចាក់"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"ផ្អាក"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"ពង្រីក"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"បង្រួម"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-kn-rIN/strings.xml b/v7/mediarouter/res/values-kn-rIN/strings.xml
index 887b2ec..970dc41 100644
--- a/v7/mediarouter/res/values-kn-rIN/strings.xml
+++ b/v7/mediarouter/res/values-kn-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"ಸಿಸ್ಟಂ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ಸಾಧನಗಳು"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ಪಾತ್ರ"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಿ"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ಬಿತ್ತರಿಸುವಿಕೆ ನಿಲ್ಲಿಸು"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ಮಾರ್ಗ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ಪ್ಲೇ ಮಾಡು"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ವಿರಾಮ"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ಬಿತ್ತರಿಸು ಬಟನ್‌"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"ಬಿತ್ತರಿಸುವಿಕೆ ನಿಲ್ಲಿಸು"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"ಮುಚ್ಚು"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ಪ್ಲೇ ಮಾಡಿ"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"ವಿರಾಮ"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"ವಿಸ್ತರಿಸು"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ಸಂಕುಚಿಸು"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
index b3a6983e..2b3455f 100644
--- a/v7/mediarouter/res/values-ko/strings.xml
+++ b/v7/mediarouter/res/values-ko/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"시스템"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"기기"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"전송"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"기기에 연결"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"기기 검색 중…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"연결 해제"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"전송 중지"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"경로 설정"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"재생"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"일시중지"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"정보가 없습니다."</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"전송 버튼"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"전송 중지"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"닫기"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"재생"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"일시중지"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"펼치기"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"접기"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ky-rKG/strings.xml b/v7/mediarouter/res/values-ky-rKG/strings.xml
index f7df56c..d7409db 100644
--- a/v7/mediarouter/res/values-ky-rKG/strings.xml
+++ b/v7/mediarouter/res/values-ky-rKG/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Түзмөктөр"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Тандалгандар"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Түзмөккө туташуу"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Түзмөктөр изделүүдө..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ажыратуу"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Тышк экранга чыгарну токтотуу"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Багыт жөндөөлөрү"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ойнотуу"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Тындыруу"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Эч маалымат жок"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Тышкы экранга чыгаруу баскычы"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Тышк экранга чыгарну токтотуу"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Жабуу"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Ойнотуу"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Тындыруу"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жайып көрсөтүү"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жыйыштыруу"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-land/dimens.xml b/v7/mediarouter/res/values-land/dimens.xml
new file mode 100644
index 0000000..ee606aa
--- /dev/null
+++ b/v7/mediarouter/res/values-land/dimens.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<resources>
+    <!-- MediaRouteController's volume group list -->
+    <eat-comment />
+    <!-- Maximum height of volume group list. -->
+    <dimen name="mr_controller_volume_group_list_max_height">132dp</dimen>
+    <!-- Height of volume group item. -->
+    <dimen name="mr_controller_volume_group_list_item_height">61dp</dimen>
+    <!-- Size of an item's icon. -->
+    <dimen name="mr_controller_volume_group_list_item_icon_size">18dp</dimen>
+</resources>
diff --git a/v7/mediarouter/res/values-lo-rLA/strings.xml b/v7/mediarouter/res/values-lo-rLA/strings.xml
index 6f8e010..a19dd69 100644
--- a/v7/mediarouter/res/values-lo-rLA/strings.xml
+++ b/v7/mediarouter/res/values-lo-rLA/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"ລະບົບ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ອຸປະກອນ"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ສົ່ງ​ສັນ​ຍານ"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ເຊື່ອມຕໍ່ຫາອຸປະກອນ"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ກຳລັງຊອກຫາອຸປະກອນ..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ຕັດການເຊື່ອມຕໍ່"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ຢຸດການສົ່ງສັນຍານ"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ການ​ຕັ້ງ​ຄ່າ​ເສັ້ນ​ທາງ"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ຫຼິ້ນ"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ຢຸດຊົ່ວຄາວ"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ບໍ່​ມີ​ຂໍ້​ມູນ​ຢູ່"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ປຸ່ມ​ຄາ​ສ​ທ໌"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"ຢຸດການຄາ​ສ​ທ໌"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"ປິດ"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ຫຼິ້ນ"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"ຢຸດຊົ່ວຄາວ"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"ຂະຫຍາຍ"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ຫຍໍ້ລົງ"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
index 0832d64..d286e0c 100644
--- a/v7/mediarouter/res/values-lt/strings.xml
+++ b/v7/mediarouter/res/values-lt/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Įrenginiai"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Perduoti"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Prijungimas prie įrenginio"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Ieškoma įrenginių…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Atjungti"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Sustabdyti perdavimą"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Maršruto nustatymai"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Leisti"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pristabdyti"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Informacija nepasiekiama"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Perdavimo mygtukas"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Sustabdyti perdavimą"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Uždaryti"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Leisti"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pristabdyti"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
index 1c20c9b..8f49d85 100644
--- a/v7/mediarouter/res/values-lv/strings.xml
+++ b/v7/mediarouter/res/values-lv/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Apraidīt"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Savienojuma izveide ar ierīci"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Notiek ierīču meklēšana..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Atvienot"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Pārtraukt apraidi"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Maršruta iestatījumi"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Atskaņot"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Apturēt"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nav pieejama informācija"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Apraides poga"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Pārtraukt apraidi"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Aizvērt"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Atskaņot"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Apturēt"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-mk-rMK/strings.xml b/v7/mediarouter/res/values-mk-rMK/strings.xml
index 1b2756f..e8ff3e7 100644
--- a/v7/mediarouter/res/values-mk-rMK/strings.xml
+++ b/v7/mediarouter/res/values-mk-rMK/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Уреди"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Емитувај"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Поврзи се со уредот"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Се пребаруваат уреди..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Исклучи се"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Запри префрлување"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Поставки на маршрутата"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Репродуцирај"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Пауза"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Нема достапни информации"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Копчето за 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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Запри го емитувањето"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Затвори"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Репродуцирај"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Паузирај"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Собери"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ml-rIN/strings.xml b/v7/mediarouter/res/values-ml-rIN/strings.xml
index 57b23f8..7dbdf5d 100644
--- a/v7/mediarouter/res/values-ml-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ml-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"കാസ്‌റ്റുചെയ്യുക"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ഉപകരണത്തിലേക്ക് കണക്റ്റുചെയ്യുക"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ഉപകരണങ്ങൾക്കായി തിരയുന്നു…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"വിച്ഛേദിക്കുക"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"റൂട്ട് ക്രമീകരണം"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"പ്ലേ ചെയ്യുക"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"താൽക്കാലികമായി നിർത്തുക"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ടാപ്പുചെയ്യുക"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"അടയ്‌ക്കുക"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"പ്ലേ ചെയ്യുക"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"തൽക്കാലം നിർത്തൂ"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"വികസിപ്പിക്കുക"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ചുരുക്കുക"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-mn-rMN/strings.xml b/v7/mediarouter/res/values-mn-rMN/strings.xml
index 1bba4d5..db6d599 100644
--- a/v7/mediarouter/res/values-mn-rMN/strings.xml
+++ b/v7/mediarouter/res/values-mn-rMN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Төхөөрөмжүүд"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Дамжуулах"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Төхөөрөмжтэй холбох"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Төхөөрөмжүүдийг хайж байна…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Салгах"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Нэвтрүүлэхийг зогсоох"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Маршрут тохиргоо"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Тоглуулах"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Түр зогсоох"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Мэдээлэл байхгүй байна"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Дамжуулах товчлуур"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Дамжуулахыг зогсоох"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Хаах"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Тоглуулах"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Түр зогсоох"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Дэлгэх"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Хураах"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-mr-rIN/strings.xml b/v7/mediarouter/res/values-mr-rIN/strings.xml
index 6b607cc..b3f9264 100644
--- a/v7/mediarouter/res/values-mr-rIN/strings.xml
+++ b/v7/mediarouter/res/values-mr-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्‍ट करा"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"डिव्हाइसला कनेक्ट करा"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"डिव्‍हाइसेस शोधत आहे…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"‍डिस्कनेक्ट करा"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्ट करणे थांबवा"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिंग्ज"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"प्ले करा"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"विराम द्या"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"कोणतीही माहिती उपलब्ध नाही"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट बटण"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"कास्ट करणे थांबवा"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"बंद करा"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"प्ले करा"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"विराम"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करा"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संकुचित करा"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ms-rMY/strings.xml b/v7/mediarouter/res/values-ms-rMY/strings.xml
index 946a514..4d7a0c8 100644
--- a/v7/mediarouter/res/values-ms-rMY/strings.xml
+++ b/v7/mediarouter/res/values-ms-rMY/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Peranti"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Barisan pelakon"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Sambung kepada peranti"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Mencari peranti..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Putuskan sambungan"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Berhenti menghantar"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Tetapan laluan"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Main"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Jeda"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Maklumat tidak tersedia"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Butang Hantar"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Berhenti menghantar"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Main"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kembangkan"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Runtuhkan"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-my-rMM/strings.xml b/v7/mediarouter/res/values-my-rMM/strings.xml
index db4a72b..9447089 100644
--- a/v7/mediarouter/res/values-my-rMM/strings.xml
+++ b/v7/mediarouter/res/values-my-rMM/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"စနစ်"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"စက်ပစ္စည်းများ"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"သရုပ်ဆောင်​များ"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"စက်တစ်ခုကို ချိတ်ဆက်ပါ"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"စက်ပစ္စည်းများကို ရှာဖွေနေပါသည်"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ချိတ်ဆက်ခြင်းရပ်တန့်ရန်"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ပုံစံသွင်းမှု ရပ်ရန်"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"လမ်းကြောင်း အပြင်အဆင်များ"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ဖွင့်ရန်"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ခဏရပ်ရန်"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"အချက်အလက် မရရှိနိုင်ပါ"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ကာစ်တ်လုပ်ရန် ခလုတ်"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"ကာစ်တ်လုပ်ခြင်း ရပ်တန့်ရန်"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"ပိတ်ရန်"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ဖွင့်ရန်"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"ခဏရပ်ရန်"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"ဖြန့်ချရန်၃"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ခေါက်သိမ်းရန်..."</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>
 </resources>
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
index 018c02f..aea341f 100644
--- a/v7/mediarouter/res/values-nb/strings.xml
+++ b/v7/mediarouter/res/values-nb/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Koble til enheten"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Søker etter enheter …"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Koble fra"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stopp castingen"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ruteinnstillinger"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spill av"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sett på pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Ingen informasjon er tilgjengelig"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-ikonet"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Stopp castingen"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Lukk"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Spill av"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Sett på pause"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utvid"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ne-rNP/strings.xml b/v7/mediarouter/res/values-ne-rNP/strings.xml
index 84ca24e..d261553 100644
--- a/v7/mediarouter/res/values-ne-rNP/strings.xml
+++ b/v7/mediarouter/res/values-ne-rNP/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"प्रणाली"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"उपकरणहरू"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"उपकरणसँग जडान गर्नुहोस्"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"उपकरणहरूका लागि खोजी गरिँदै..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"विच्छेदन गर्नुहोस्"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्टिंग रोक्नुहोस्"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिङ"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"बजाउनुहोस्"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"रोक्नुहोस्"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"जानकारी उपलब्ध छैन"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"casting रोक्नुहोस्"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"बन्द गर्नुहोस्"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"बजाउनुहोस्"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"रोक्नुहोस्"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तार गर्नुहोस्"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त पार्नुहोस्"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
index c317820e..7843b52 100644
--- a/v7/mediarouter/res/values-nl/strings.xml
+++ b/v7/mediarouter/res/values-nl/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Systeem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Apparaten"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Casten"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Verbinding maken met apparaat"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Zoeken naar apparaten…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Verbinding verbreken"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Casten stoppen"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route-instellingen"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Afspelen"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Onderbreken"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Geen informatie beschikbaar"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-icoon"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Casten stoppen"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Sluiten"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Afspelen"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Onderbreken"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Uitvouwen"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Samenvouwen"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa-rIN/strings.xml
index dc4e9d0..55dfd88 100644
--- a/v7/mediarouter/res/values-pa-rIN/strings.xml
+++ b/v7/mediarouter/res/values-pa-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"ਸਿਸਟਮ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ਡਿਵਾਈਸਾਂ"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ਜੋੜੋ"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ਡਿਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ਡਿਵਾਈਸਾਂ ਦੀ ਖੋਜ ਕਰ ਰਿਹਾ ਹੈ…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ਜੋੜਨਾ ਰੋਕੋ"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ਰੂਟ ਸੈਟਿੰਗਾਂ"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ਪਲੇ ਕਰੋ"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ਰੋਕੋ"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ਕੋਈ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ਕਾਸਟ ਬਟਨ"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"ਜੋੜਨਾ ਰੋਕੋ"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"ਬੰਦ ਕਰੋ"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ਪਲੇ ਕਰੋ"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"ਰੋਕੋ"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ਬੰਦ ਕਰੋ"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
index e6f4780..c6e7f8a 100644
--- a/v7/mediarouter/res/values-pl/strings.xml
+++ b/v7/mediarouter/res/values-pl/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Przesyłaj"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Połącz z urządzeniem"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Szukam urządzeń…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Rozłącz"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zakończ przesyłanie"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ustawienia trasy"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Odtwórz"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Wstrzymaj"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Brak informacji"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Przycisk Cast"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Zatrzymaj przesyłanie"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zamknij"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Odtwórz"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Wstrzymaj"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozwiń"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zwiń"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/res/values-pt-rBR/strings.xml
index 629c63f..17e64f0 100644
--- a/v7/mediarouter/res/values-pt-rBR/strings.xml
+++ b/v7/mediarouter/res/values-pt-rBR/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar ao dispositivo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Procurando dispositivos…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interromper transmissão"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configurações de rota"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nenhuma informação disponível"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Interromper transmissão"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
index 90ce270..3c9d4cb 100644
--- a/v7/mediarouter/res/values-pt-rPT/strings.xml
+++ b/v7/mediarouter/res/values-pt-rPT/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Ligar ao dispositivo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"A pesquisar dispositivos…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desassociar"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Parar a transmissão"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Definições de trajeto"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Colocar em pausa"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nenhuma informação disponível"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Interromper a transmissão"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Interromper"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Reduzir"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
index 629c63f..17e64f0 100644
--- a/v7/mediarouter/res/values-pt/strings.xml
+++ b/v7/mediarouter/res/values-pt/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar ao dispositivo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Procurando dispositivos…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interromper transmissão"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configurações de rota"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nenhuma informação disponível"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Interromper transmissão"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
index 9e7fdb9..20c3b71 100644
--- a/v7/mediarouter/res/values-ro/strings.xml
+++ b/v7/mediarouter/res/values-ro/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispozitive"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Trimiteți"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectați-vă la dispozitiv"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Se caută dispozitive..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Deconectați-vă"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Nu mai proiectați"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Setări pentru traseu"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Redați"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Întrerupeți"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nu sunt disponibile informații"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Butonul de proiecție"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Opriți proiecția"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Închideți"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Redați"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Întrerupeți"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
index 381f5ec..5a47ec6 100644
--- a/v7/mediarouter/res/values-ru/strings.xml
+++ b/v7/mediarouter/res/values-ru/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Транслировать."</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Подключение к устройству"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Поиск устройств…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Отключить"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Остановить трансляцию"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Настройки передачи файлов"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Воспроизвести."</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Приостановить."</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Данных нет"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляции"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Остановить трансляцию"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Закрыть"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Воспроизвести"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Приостановить"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Развернуть"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свернуть"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-si-rLK/strings.xml b/v7/mediarouter/res/values-si-rLK/strings.xml
index b8949ec..45f67ff 100644
--- a/v7/mediarouter/res/values-si-rLK/strings.xml
+++ b/v7/mediarouter/res/values-si-rLK/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"පද්ධතිය"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"උපාංග"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"උපාංගයට සම්බන්ධ වන්න"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"උපාංග සඳහා සොයමින්…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"විසන්ධි කරන්න"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"කාස්ට් කිරීම නවත්වන්න"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ගමන් මගේ සැකසීම්"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ධාවනය කරන්න"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"විරාමය"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ලබා ගත හැකි තොරතුරු නොමැත"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"විකාශ බොත්තම"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"විකාශ කිරීම නවත්වන්න"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"වසන්න"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ධාවනය කරන්න"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"විරාම ගන්වන්න"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"දිග හරින්න"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"හකුළන්න"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
index cc9336e..df95e00 100644
--- a/v7/mediarouter/res/values-sk/strings.xml
+++ b/v7/mediarouter/res/values-sk/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Prenášať"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Pripojenie k zariadeniu"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Prebieha vyhľadávanie zariadení…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Odpojiť"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zastaviť prenášanie"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavenia trasy"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Prehrať"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pozastaviť"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nie sú k dispozícii žiadne informácie"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačidlo prenosu"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Zastaviť prenos"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zavrieť"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Prehrať"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pozastaviť"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbaliť"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zbaliť"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
index f5da487..6425222 100644
--- a/v7/mediarouter/res/values-sl/strings.xml
+++ b/v7/mediarouter/res/values-sl/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Naprave"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Predvajanje"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Povezovanje z napravo"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Iskanje naprav …"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Prekini povezavo"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ustavi predvajanje"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavitve poti"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Predvajaj"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Zaustavi"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Podatki niso na voljo"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za predvajanje"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Ustavi predvajanje"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Zapri"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Predvajanje"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Zaustavi"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-sq-rAL/strings.xml b/v7/mediarouter/res/values-sq-rAL/strings.xml
index de3a1c8..6f375cf 100644
--- a/v7/mediarouter/res/values-sq-rAL/strings.xml
+++ b/v7/mediarouter/res/values-sq-rAL/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistemi"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Pajisjet"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmeto"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Lidhu me pajisjen"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Po kërkon për pajisje…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Shkëputu"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ndalo transmetimin"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Cilësimet e rrugës"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Luaj"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pauzë"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nuk jepet asnjë informacion"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Butoni i transmetimit"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Ndalo transmetimin"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Mbyll"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Luaj"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pauzë"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zgjeroje"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Palose"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index 1ca7107..26a36a9 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Уређаји"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Пребацуј"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Повежите са уређајем"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Претраживање уређаја…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Прекини везу"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Заустави пребацивање"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Подешавања путање"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Пусти"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Паузирај"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Нису доступне никакве информације"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Дугме Пребаци"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Заустави пребацивање"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Затвори"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Пусти"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Паузирај"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Скупи"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
index 3721864..3e8c47b 100644
--- a/v7/mediarouter/res/values-sv/strings.xml
+++ b/v7/mediarouter/res/values-sv/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Casta"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Anslut till enhet"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Söker efter enheter ..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Koppla från"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Sluta casta"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Inställningar för omdirigering"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spela upp"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Det finns ingen information"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knappen"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Sluta casta"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Stäng"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Spela upp"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
index b9208f3..38fdb45 100644
--- a/v7/mediarouter/res/values-sw/strings.xml
+++ b/v7/mediarouter/res/values-sw/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Mfumo"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Vifaa"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Tuma"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Unganisha kwenye kifaa"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Inatafuta vifaa..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Tenganisha"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Acha kutuma"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Mipangilio ya njia"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Google Play"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sitisha"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Hakuna maelezo yaliyopatikana"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Kitufe cha kutuma"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Acha kutuma"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Funga"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Cheza"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Sitisha"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Panua"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Kunja"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-sw600dp/dimens.xml b/v7/mediarouter/res/values-sw600dp/dimens.xml
index 5b29058..ee07732 100644
--- a/v7/mediarouter/res/values-sw600dp/dimens.xml
+++ b/v7/mediarouter/res/values-sw600dp/dimens.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -15,5 +15,10 @@
 -->
 
 <resources>
-    <dimen name="mr_media_route_controller_art_max_height">480dp</dimen>
-</resources>
\ No newline at end of file
+    <!-- The platform's desired fixed width for a dialog along the major axis
+         (the screen is in landscape). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="mr_dialog_fixed_width_major">60%</item>
+    <!-- The platform's desired fixed width for a dialog along the minor axis
+         (the screen is in portrait). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="mr_dialog_fixed_width_minor">90%</item>
+</resources>
diff --git a/v7/mediarouter/res/values-sw720dp/dimens.xml b/v7/mediarouter/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000..ab6131f
--- /dev/null
+++ b/v7/mediarouter/res/values-sw720dp/dimens.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<resources>
+    <!-- The platform's desired fixed width for a dialog along the major axis
+         (the screen is in landscape). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="mr_dialog_fixed_width_major">50%</item>
+    <!-- The platform's desired fixed width for a dialog along the minor axis
+         (the screen is in portrait). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="mr_dialog_fixed_width_minor">70%</item>
+</resources>
diff --git a/v7/mediarouter/res/values-ta-rIN/strings.xml b/v7/mediarouter/res/values-ta-rIN/strings.xml
index 7b0c13b..6147b75 100644
--- a/v7/mediarouter/res/values-ta-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ta-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"அமைப்பு"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"அனுப்பு"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"சாதனத்துடன் இணைக்கவும்"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"சாதனங்களைத் தேடுகிறது..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"துண்டி"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"அனுப்புவதை நிறுத்து"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"வழி அமைப்புகள்"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"இயக்கு"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"இடைநிறுத்து"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"தகவல் எதுவுமில்லை"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"அனுப்புதல் பொத்தான்"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"அனுப்புவதை நிறுத்து"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"மூடும்"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"இயக்கும்"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"இடைநிறுத்தும்"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"விரிவாக்கு"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"சுருக்கு"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-te-rIN/strings.xml b/v7/mediarouter/res/values-te-rIN/strings.xml
index 97b2510..73c75f4 100644
--- a/v7/mediarouter/res/values-te-rIN/strings.xml
+++ b/v7/mediarouter/res/values-te-rIN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"సిస్టమ్"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"పరికరాలు"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ప్రసారం చేయండి"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"పరికరానికి కనెక్ట్ చేయండి"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"పరికరాల కోసం శోధిస్తోంది…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"డిస్‌కనెక్ట్ చేయి"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ప్రసారాన్ని ఆపివేయి"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"మార్గ సెట్టింగ్‌లు"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ప్లే చేయి"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"పాజ్ చేయి"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"సమాచారం అందుబాటులో లేదు"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ప్రసారం చేయి బటన్"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"ప్రసారాన్ని ఆపివేయి"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"మూసివేస్తుంది"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"ప్లే చేస్తుంది"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"పాజ్ చేస్తుంది"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"విస్తరింపజేస్తుంది"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"కుదిస్తుంది"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
index 9122e27..fdf0957 100644
--- a/v7/mediarouter/res/values-th/strings.xml
+++ b/v7/mediarouter/res/values-th/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"ระบบ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"อุปกรณ์"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"แคสต์"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"เชื่อมต่อกับอุปกรณ์"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"กำลังค้นหาอุปกรณ์…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ยกเลิกการเชื่อมต่อ"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"หยุดการส่ง"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"การตั้งค่าเส้นทาง"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"เล่น"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"หยุดชั่วคราว"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ไม่มีข้อมูล"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ปุ่ม \"แคสต์\""</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"หยุดการแคสต์"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"ปิด"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"เล่น"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"หยุดชั่วคราว"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"ขยาย"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ยุบ"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
index b6ce45e..7c04b33 100644
--- a/v7/mediarouter/res/values-tl/strings.xml
+++ b/v7/mediarouter/res/values-tl/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"I-cast"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Kumonekta sa device"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Naghahanap ng mga device…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Idiskonekta"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Itigil ang pagca-cast"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Mga setting ng ruta"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"I-play"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"I-pause"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Walang available na impormasyon"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Button na I-cast"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Itigil ang pagca-cast"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Isara"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"I-play"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"I-pause"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
index d8d398c..f8316f4 100644
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ b/v7/mediarouter/res/values-tr/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Yayınla"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Cihaza bağlanın"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Cihaz arayın…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Bağlantıyı kes"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Yayını durdur"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Rota ayarları"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Oynat"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Duraklat"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Bilgi yok"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Yayın düğmesi"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Yayını durdur"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Kapat"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Oynat"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Duraklat"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/res/values-uk/strings.xml
index beab592..fd4e0d0 100644
--- a/v7/mediarouter/res/values-uk/strings.xml
+++ b/v7/mediarouter/res/values-uk/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Пристрої"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Транслювати"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Під’єднатися до пристрою"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Пошук пристроїв…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Від’єднатися"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Зупинити трансляцію"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Налаштування маршруту"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Відтворити"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Призупинити"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Немає даних"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляції"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Припинити трансляцію"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Закрити"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Відтворити"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Призупинити"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Розгорнути"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згорнути"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-ur-rPK/strings.xml b/v7/mediarouter/res/values-ur-rPK/strings.xml
index 9784c4a..afd5534 100644
--- a/v7/mediarouter/res/values-ur-rPK/strings.xml
+++ b/v7/mediarouter/res/values-ur-rPK/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"سسٹم"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"آلات"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"کاسٹ کریں"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"آلہ سے مربوط ہوں"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"آلات تلاش کر رہا ہے…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"غیر مربوط کریں"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"کاسٹ کرنا بند کریں"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"روٹ کی ترتیبات"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"چلائیں"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"موقوف کریں"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"کوئی معلومات دستیاب نہیں"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"کاسٹ کرنے کا بٹن"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"کاسٹ کرنا بند کریں"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"بند کریں"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"چلائیں"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"موقوف کریں"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"پھیلائیں"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"سکیڑیں"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-uz-rUZ/strings.xml b/v7/mediarouter/res/values-uz-rUZ/strings.xml
index e39a3a8..c13b06b 100644
--- a/v7/mediarouter/res/values-uz-rUZ/strings.xml
+++ b/v7/mediarouter/res/values-uz-rUZ/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Tizim"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Qurilmalar"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Translatsiya qilish"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Qurilmaga ulanish"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Qurilmalar izlanmoqda…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Uzish"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Translatsiyani to‘xtatish"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Yo‘naltirish sozlamalari"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ijro qilish"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"To‘xtatib turish"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Hech qanday ma’lumot yo‘q"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Translatsiya tugmasi"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Translatsiyani to‘xtatish"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Yopish"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Boshlash"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"To‘xtatib turish"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
index b2c8abd..3301cee 100644
--- a/v7/mediarouter/res/values-vi/strings.xml
+++ b/v7/mediarouter/res/values-vi/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <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_media_route_button_content_description" msgid="8327680881775995150">"Truyền"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Kết nối với thiết bị"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Đang tìm kiếm thiết bị…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ngắt kết nối"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ngừng truyền"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Cài đặt tuyến đường"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Phát"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Tạm dừng"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Không có thông tin nào"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Nút truyền"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Dừng truyền"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Đóng"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Phát"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Tạm dừng"</string>
+    <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_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>
 </resources>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index c58162f..cdd66f53 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"系统"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"设备"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投射"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"连接到设备"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜索设备…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"断开连接"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投射"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由设置"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暂停"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"没有任何相关信息"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"投射按钮"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"停止投射"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"关闭"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"播放"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"暂停"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"展开"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折叠"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
index 2c9f671..873e5ce 100644
--- a/v7/mediarouter/res/values-zh-rHK/strings.xml
+++ b/v7/mediarouter/res/values-zh-rHK/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投放"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"連線至裝置"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜尋裝置…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"中斷連線"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投放"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由設定"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暫停"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"沒有詳細資料"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"停止投放"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"關閉"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"播放"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"暫停"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
index 13dfd11..27755e7 100644
--- a/v7/mediarouter/res/values-zh-rTW/strings.xml
+++ b/v7/mediarouter/res/values-zh-rTW/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投放"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"連線至裝置"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜尋裝置..."</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"中斷連線"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投放"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由設定"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暫停"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"沒有可用的資訊"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"停止投放"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"關閉"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"播放"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"暫停"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</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>
 </resources>
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
index ec9a68a..f513fd4 100644
--- a/v7/mediarouter/res/values-zu/strings.xml
+++ b/v7/mediarouter/res/values-zu/strings.xml
@@ -18,13 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mr_system_route_name" msgid="5441529851481176817">"Isistimu"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Amadivayisi"</string>
-    <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Abalingisi"</string>
-    <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Xhumeka kudivayisi"</string>
-    <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Iseshela amadivayisi…"</string>
-    <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Nqamula"</string>
-    <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Misa ukusakaza"</string>
-    <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Izilungiselelo zomzila"</string>
-    <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Dlala"</string>
-    <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Misa isikhashana"</string>
-    <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Alukho ulwazi olutholakalayo"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Inkinobho ye-Cast"</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>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Misa ukusakaza"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Vala"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Dlala"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Misa isikhashana"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Nweba"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Goqa"</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>
 </resources>
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/res/values/attrs.xml
index 9f5f8ac..81073dc 100644
--- a/v7/mediarouter/res/values/attrs.xml
+++ b/v7/mediarouter/res/values/attrs.xml
@@ -26,12 +26,26 @@
         <attr name="android:minHeight" />
     </declare-styleable>
 
+    <attr name="MediaRouteControllerWindowBackground" format="reference" />
     <attr name="mediaRouteButtonStyle" format="reference" />
     <attr name="mediaRouteOffDrawable" format="reference" />
     <attr name="mediaRouteConnectingDrawable" format="reference" />
     <attr name="mediaRouteOnDrawable" format="reference" />
-    <attr name="mediaRouteSettingsDrawable" format="reference" />
+    <attr name="mediaRouteCloseDrawable" format="reference" />
     <attr name="mediaRoutePlayDrawable" format="reference" />
     <attr name="mediaRoutePauseDrawable" format="reference" />
     <attr name="mediaRouteCastDrawable" format="reference" />
-</resources>
\ No newline at end of file
+    <attr name="mediaRouteAudioTrackDrawable" format="reference" />
+    <attr name="mediaRouteDefaultIconDrawable" format="reference" />
+    <attr name="mediaRouteBluetoothIconDrawable" format="reference" />
+    <attr name="mediaRouteTvIconDrawable" format="reference" />
+    <attr name="mediaRouteSpeakerIconDrawable" format="reference" />
+    <attr name="mediaRouteSpeakerGroupIconDrawable" format="reference" />
+    <attr name="mediaRouteChooserPrimaryTextStyle" format="reference" />
+    <attr name="mediaRouteChooserSecondaryTextStyle" format="reference" />
+    <attr name="mediaRouteControllerTitleTextStyle" format="reference" />
+    <attr name="mediaRouteControllerPrimaryTextStyle" format="reference" />
+    <attr name="mediaRouteControllerSecondaryTextStyle" format="reference" />
+    <attr name="mediaRouteExpandGroupDrawable" format="reference" />
+    <attr name="mediaRouteCollapseGroupDrawable" format="reference" />
+</resources>
diff --git a/v7/mediarouter/res/values/dimens.xml b/v7/mediarouter/res/values/dimens.xml
index e687c82..10e5751 100644
--- a/v7/mediarouter/res/values/dimens.xml
+++ b/v7/mediarouter/res/values/dimens.xml
@@ -15,5 +15,25 @@
 -->
 
 <resources>
-    <dimen name="mr_media_route_controller_art_max_height">320dp</dimen>
-</resources>
\ No newline at end of file
+    <!-- Dialog size -->
+    <eat-comment />
+    <!-- The platform's desired fixed width for a dialog along the major axis
+         (the screen is in landscape). This may be either a fraction or a dimension.-->
+    <dimen name="mr_dialog_fixed_width_major">320dp</dimen>
+    <!-- The platform's desired fixed width for a dialog along the minor axis
+         (the screen is in portrait). This may be either a fraction or a dimension.-->
+    <dimen name="mr_dialog_fixed_width_minor">320dp</dimen>
+
+    <!-- MediaRouteController's volume group list -->
+    <eat-comment />
+    <!-- Maximum height of volume group list. -->
+    <dimen name="mr_controller_volume_group_list_max_height">288dp</dimen>
+    <!-- Height of volume group item. -->
+    <dimen name="mr_controller_volume_group_list_item_height">68dp</dimen>
+    <!-- Size of an item's icon. -->
+    <dimen name="mr_controller_volume_group_list_item_icon_size">24dp</dimen>
+
+    <dimen name="mr_controller_volume_group_list_padding_top">16dp</dimen>
+    <!-- Group list expand/collapse animation duration. -->
+    <integer name="mr_controller_volume_group_list_animation_duration_ms">200</integer>
+</resources>
diff --git a/v7/mediarouter/res/values/strings.xml b/v7/mediarouter/res/values/strings.xml
index a87ce4f..fad0408 100644
--- a/v7/mediarouter/res/values/strings.xml
+++ b/v7/mediarouter/res/values/strings.xml
@@ -23,29 +23,41 @@
 
     <!-- Content description of a MediaRouteButton for accessibility support.
         Cast is the standard android verb for sending content to a remote device. [CHAR LIMIT=50] -->
-    <string name="mr_media_route_button_content_description">Cast</string>
+    <string name="mr_button_content_description">Cast button</string>
 
     <!-- Title of the media route chooser dialog. [CHAR LIMIT=30] -->
-    <string name="mr_media_route_chooser_title">Connect to device</string>
+    <string name="mr_chooser_title">Cast to</string>
 
     <!-- Placeholder text to show when no devices have been found. [CHAR LIMIT=50] -->
-    <string name="mr_media_route_chooser_searching">Searching for devices\u2026</string>
+    <string name="mr_chooser_searching">Finding devices</string>
 
     <!-- Button to disconnect from a media route.  [CHAR LIMIT=30] -->
-    <string name="mr_media_route_controller_disconnect">Disconnect</string>
+    <string name="mr_controller_disconnect">Disconnect</string>
 
-    <!-- Button to stop playback and disconnect from a media route.  [CHAR LIMIT=30] -->
-    <string name="mr_media_route_controller_stop">Stop casting</string>
+    <!-- Button to stop playback and disconnect from a media route. [CHAR LIMIT=30] -->
+    <string name="mr_controller_stop">Stop casting</string>
 
-    <!-- Description for a button that takes you to settings for the active route -->
-    <string name="mr_media_route_controller_settings_description">Route settings</string>
+    <!-- Content description for accessibility (not shown on the screen): dialog close button. [CHAR LIMIT=NONE] -->
+    <string name="mr_controller_close_description">Close</string>
 
-    <!-- Accessibility description for the play button -->
-    <string name="mr_media_route_controller_play">Play</string>
+    <!-- Content description for accessibility (not shown on the screen): media play button. [CHAR LIMIT=NONE] -->
+    <string name="mr_controller_play">Play</string>
 
-    <!-- Accessibility description for the pause button -->
-    <string name="mr_media_route_controller_pause">Pause</string>
+    <!-- Content description for accessibility (not shown on the screen): media pause button. [CHAR LIMIT=NONE] -->
+    <string name="mr_controller_pause">Pause</string>
+
+    <!-- Content description for accessibility (not shown on the screen): group expand button. Pressing button shows group members of a selected route group. [CHAR LIMIT=NONE] -->
+    <string name="mr_controller_expand_group">Expand</string>
+
+    <!-- Content description for accessibility (not shown on the screen): group collapse button. Pressing button hides group members of a selected route group. [CHAR LIMIT=NONE] -->
+    <string name="mr_controller_collapse_group">Collapse</string>
+
+    <!-- Placeholder text to show when no media have been selected for playback. [CHAR LIMIT=50] -->
+    <string name="mr_controller_no_media_selected">No media selected</string>
 
     <!-- Placeholder text to show when no title/description have been found for a given song/video. [CHAR LIMIT=50] -->
-    <string name="mr_media_route_controller_no_info_available">No info available</string>
+    <string name="mr_controller_no_info_available">No info available</string>
+
+    <!-- Placeholder text indicating that the user is currently casting screen. [CHAR LIMIT=50] -->
+    <string name="mr_controller_casting_screen">Casting screen</string>
 </resources>
diff --git a/v7/mediarouter/res/values/styles.xml b/v7/mediarouter/res/values/styles.xml
index 9be8545..18f954d 100644
--- a/v7/mediarouter/res/values/styles.xml
+++ b/v7/mediarouter/res/values/styles.xml
@@ -17,21 +17,83 @@
 <resources>
     <style name="Widget.MediaRouter.MediaRouteButton"
             parent="Widget.AppCompat.ActionButton">
-        <item name="android:minWidth">56dp</item>
-        <item name="android:minHeight">48dp</item>
-        <item name="android:padding">0dp</item>
-        <item name="android:focusable">true</item>
-        <item name="android:contentDescription">@string/mr_media_route_button_content_description</item>
+        <item name="android:contentDescription">@string/mr_button_content_description</item>
         <item name="externalRouteEnabledDrawable">@drawable/mr_ic_media_route_mono_dark</item>
     </style>
 
     <style name="Widget.MediaRouter.Light.MediaRouteButton"
             parent="Widget.AppCompat.Light.ActionButton">
-        <item name="android:minWidth">56dp</item>
-        <item name="android:minHeight">48dp</item>
-        <item name="android:padding">0dp</item>
-        <item name="android:focusable">true</item>
-        <item name="android:contentDescription">@string/mr_media_route_button_content_description</item>
+        <item name="android:contentDescription">@string/mr_button_content_description</item>
         <item name="externalRouteEnabledDrawable">@drawable/mr_ic_media_route_mono_light</item>
     </style>
-</resources>
\ No newline at end of file
+
+    <!-- MediaRouteChooserDialog text styles -->
+    <style name="Widget.MediaRouter.ChooserText" parent="">
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ChooserText.Primary">
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ChooserText.Secondary">
+        <item name="android:textSize">14sp</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ChooserText.Primary.Dark">
+        <item name="android:textColor">#FFFFFFFF</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ChooserText.Primary.Light">
+        <item name="android:textColor">#DE000000</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ChooserText.Secondary.Dark">
+        <item name="android:textColor">#8AFFFFFF</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ChooserText.Secondary.Light">
+        <item name="android:textColor">#8A000000</item>
+    </style>
+
+    <!-- MediaRouteControllerDialog text styles -->
+    <style name="Widget.MediaRouter.ControllerText" parent="Widget.MediaRouter.ChooserText" />
+
+    <style name="Widget.MediaRouter.ControllerText.Title">
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:textSize">20sp</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Primary">
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Secondary">
+        <item name="android:textSize">14sp</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Title.Dark">
+        <item name="android:textColor">#FFFFFFFF</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Title.Light">
+        <item name="android:textColor">#DE000000</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Primary.Dark">
+        <item name="android:textColor">#FFFFFFFF</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Primary.Light">
+        <item name="android:textColor">#DE000000</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Secondary.Dark">
+        <item name="android:textColor">#FFFFFFFF</item>
+    </style>
+
+    <style name="Widget.MediaRouter.ControllerText.Secondary.Light">
+        <item name="android:textColor">#DE000000</item>
+    </style>
+</resources>
diff --git a/v7/mediarouter/res/values/themes.xml b/v7/mediarouter/res/values/themes.xml
index 85d0a8b..95aac1c 100644
--- a/v7/mediarouter/res/values/themes.xml
+++ b/v7/mediarouter/res/values/themes.xml
@@ -17,27 +17,70 @@
 <resources>
 
     <style name="Theme.MediaRouter" parent="">
+        <item name="android:windowNoTitle">false</item>
         <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.MediaRouteButton</item>
 
+        <item name="MediaRouteControllerWindowBackground">@drawable/mr_dialog_material_background_dark</item>
         <item name="mediaRouteOffDrawable">@drawable/ic_media_route_off_mono_dark</item>
         <item name="mediaRouteConnectingDrawable">@drawable/mr_ic_media_route_connecting_mono_dark</item>
         <item name="mediaRouteOnDrawable">@drawable/ic_media_route_on_mono_dark</item>
-        <item name="mediaRouteSettingsDrawable">@drawable/mr_ic_settings_dark</item>
+        <item name="mediaRouteCloseDrawable">@drawable/mr_ic_close_dark</item>
         <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_dark</item>
         <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_dark</item>
         <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_dark</item>
+        <item name="mediaRouteAudioTrackDrawable">@drawable/ic_audiotrack</item>
+        <item name="mediaRouteDefaultIconDrawable">@drawable/ic_cast_white</item>
+        <item name="mediaRouteBluetoothIconDrawable">@drawable/ic_bluetooth_white</item>
+        <item name="mediaRouteTvIconDrawable">@drawable/ic_tv_dark</item>
+        <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_speaker_dark</item>
+        <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_speaker_group_dark</item>
+        <item name="mediaRouteChooserPrimaryTextStyle">@style/Widget.MediaRouter.ChooserText.Primary.Dark</item>
+        <item name="mediaRouteChooserSecondaryTextStyle">@style/Widget.MediaRouter.ChooserText.Secondary.Dark</item>
+        <item name="mediaRouteControllerTitleTextStyle">@style/Widget.MediaRouter.ControllerText.Title.Dark</item>
+        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Dark</item>
+        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Dark</item>
     </style>
 
-    <style name="Theme.MediaRouter.Light" parent="">
-        <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.Light.MediaRouteButton</item>
-
-        <item name="mediaRouteOffDrawable">@drawable/ic_cast_off_light</item>
-        <item name="mediaRouteConnectingDrawable">@drawable/mr_ic_media_route_connecting_mono_light</item>
-        <item name="mediaRouteOnDrawable">@drawable/ic_cast_on_light</item>
-        <item name="mediaRouteSettingsDrawable">@drawable/mr_ic_settings_light</item>
+    <style name="Theme.MediaRouter.LightControlPanel">
         <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_light</item>
         <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_light</item>
         <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_light</item>
+        <item name="mediaRouteAudioTrackDrawable">@drawable/mr_ic_audiotrack_light</item>
+        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Light</item>
+        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Light</item>
+    </style>
+
+    <style name="Theme.MediaRouter.Light">
+        <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.Light.MediaRouteButton</item>
+
+        <item name="MediaRouteControllerWindowBackground">@drawable/mr_dialog_material_background_light</item>
+        <item name="mediaRouteOffDrawable">@drawable/ic_cast_off_light</item>
+        <item name="mediaRouteConnectingDrawable">@drawable/mr_ic_media_route_connecting_mono_light</item>
+        <item name="mediaRouteOnDrawable">@drawable/ic_cast_on_light</item>
+        <item name="mediaRouteCloseDrawable">@drawable/mr_ic_close_light</item>
+        <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_light</item>
+        <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_light</item>
+        <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_light</item>
+        <item name="mediaRouteAudioTrackDrawable">@drawable/mr_ic_audiotrack_light</item>
+        <item name="mediaRouteDefaultIconDrawable">@drawable/ic_cast_grey</item>
+        <item name="mediaRouteBluetoothIconDrawable">@drawable/ic_bluetooth_grey</item>
+        <item name="mediaRouteTvIconDrawable">@drawable/ic_tv_light</item>
+        <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_speaker_light</item>
+        <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_speaker_group_light</item>
+        <item name="mediaRouteChooserPrimaryTextStyle">@style/Widget.MediaRouter.ChooserText.Primary.Light</item>
+        <item name="mediaRouteChooserSecondaryTextStyle">@style/Widget.MediaRouter.ChooserText.Secondary.Light</item>
+        <item name="mediaRouteControllerTitleTextStyle">@style/Widget.MediaRouter.ControllerText.Title.Light</item>
+        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Light</item>
+        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Light</item>
+    </style>
+
+    <style name="Theme.MediaRouter.Light.DarkControlPanel">
+        <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_dark</item>
+        <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_dark</item>
+        <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_dark</item>
+        <item name="mediaRouteAudioTrackDrawable">@drawable/ic_audiotrack</item>
+        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Dark</item>
+        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Dark</item>
     </style>
 
 </resources>
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
index 379ba80..c44e8d2 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
@@ -120,7 +120,8 @@
     }
 
     public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(MediaRouterThemeHelper.createThemedContext(context), attrs, defStyleAttr);
+        super(MediaRouterThemeHelper.createThemedContext(context, defStyleAttr), attrs,
+                defStyleAttr);
         context = getContext();
 
         mRouter = MediaRouter.getInstance(context);
@@ -431,40 +432,40 @@
         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
 
-        final int minWidth = Math.max(mMinWidth,
-                mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicWidth() : 0);
-        final int minHeight = Math.max(mMinHeight,
-                mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicHeight() : 0);
+        final int width = Math.max(mMinWidth, mRemoteIndicator != null ?
+                mRemoteIndicator.getIntrinsicWidth() + getPaddingLeft() + getPaddingRight() : 0);
+        final int height = Math.max(mMinHeight, mRemoteIndicator != null ?
+                mRemoteIndicator.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom() : 0);
 
-        int width;
+        int measuredWidth;
         switch (widthMode) {
             case MeasureSpec.EXACTLY:
-                width = widthSize;
+                measuredWidth = widthSize;
                 break;
             case MeasureSpec.AT_MOST:
-                width = Math.min(widthSize, minWidth + getPaddingLeft() + getPaddingRight());
+                measuredWidth = Math.min(widthSize, width);
                 break;
             default:
             case MeasureSpec.UNSPECIFIED:
-                width = minWidth + getPaddingLeft() + getPaddingRight();
+                measuredWidth = width;
                 break;
         }
 
-        int height;
+        int measuredHeight;
         switch (heightMode) {
             case MeasureSpec.EXACTLY:
-                height = heightSize;
+                measuredHeight = heightSize;
                 break;
             case MeasureSpec.AT_MOST:
-                height = Math.min(heightSize, minHeight + getPaddingTop() + getPaddingBottom());
+                measuredHeight = Math.min(heightSize, height);
                 break;
             default:
             case MeasureSpec.UNSPECIFIED:
-                height = minHeight + getPaddingTop() + getPaddingBottom();
+                measuredHeight = height;
                 break;
         }
 
-        setMeasuredDimension(width, height);
+        setMeasuredDimension(measuredWidth, measuredHeight);
     }
 
     @Override
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
index 779ae8b..5856f38 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
@@ -16,26 +16,40 @@
 
 package android.support.v7.app;
 
+import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED;
+import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING;
+
 import android.app.Dialog;
 import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.Bundle;
+import android.preference.PreferenceManager;
 import android.support.annotation.NonNull;
-import android.support.v7.media.MediaRouter;
 import android.support.v7.media.MediaRouteSelector;
+import android.support.v7.media.MediaRouter;
 import android.support.v7.mediarouter.R;
 import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.Window;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
+import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -48,6 +62,8 @@
  * @see MediaRouteActionProvider
  */
 public class MediaRouteChooserDialog extends Dialog {
+    private static final String TAG = "MediaRouteChooserDialog";
+
     private final MediaRouter mRouter;
     private final MediaRouterCallback mCallback;
 
@@ -62,7 +78,7 @@
     }
 
     public MediaRouteChooserDialog(Context context, int theme) {
-        super(MediaRouterThemeHelper.createThemedContext(context), theme);
+        super(MediaRouterThemeHelper.createThemedContext(context, theme), theme);
         context = getContext();
 
         mRouter = MediaRouter.getInstance(context);
@@ -138,22 +154,25 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
+        setContentView(R.layout.mr_chooser_dialog);
+        setTitle(R.string.mr_chooser_title);
 
-        setContentView(R.layout.mr_media_route_chooser_dialog);
-        setTitle(R.string.mr_media_route_chooser_title);
-
-        // Must be called after setContentView.
-        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
-                MediaRouterThemeHelper.getThemeResource(
-                        getContext(), R.attr.mediaRouteOffDrawable));
-
-        mRoutes = new ArrayList<MediaRouter.RouteInfo>();
+        mRoutes = new ArrayList<>();
         mAdapter = new RouteAdapter(getContext(), mRoutes);
-        mListView = (ListView)findViewById(R.id.media_route_list);
+        mListView = (ListView)findViewById(R.id.mr_chooser_list);
         mListView.setAdapter(mAdapter);
         mListView.setOnItemClickListener(mAdapter);
         mListView.setEmptyView(findViewById(android.R.id.empty));
+
+        updateLayout();
+    }
+
+    /**
+     * Sets the width of the dialog. Also called when configuration changes.
+     */
+    void updateLayout() {
+        getWindow().setLayout(MediaRouteDialogHelper.getDialogWidth(getContext()),
+                ViewGroup.LayoutParams.WRAP_CONTENT);
     }
 
     @Override
@@ -181,6 +200,7 @@
             mRoutes.clear();
             mRoutes.addAll(mRouter.getRoutes());
             onFilterRoutes(mRoutes);
+            RouteComparator.loadRouteUsageScores(getContext(), mRoutes);
             Collections.sort(mRoutes, RouteComparator.sInstance);
             mAdapter.notifyDataSetChanged();
         }
@@ -189,10 +209,27 @@
     private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo>
             implements ListView.OnItemClickListener {
         private final LayoutInflater mInflater;
+        private final Drawable mDefaultIcon;
+        private final Drawable mBluetoothIcon;
+        private final Drawable mTvIcon;
+        private final Drawable mSpeakerIcon;
+        private final Drawable mSpeakerGroupIcon;
 
         public RouteAdapter(Context context, List<MediaRouter.RouteInfo> routes) {
             super(context, 0, routes);
             mInflater = LayoutInflater.from(context);
+            TypedArray styledAttributes = getContext().obtainStyledAttributes(new int[] {
+                    R.attr.mediaRouteDefaultIconDrawable,
+                    R.attr.mediaRouteBluetoothIconDrawable,
+                    R.attr.mediaRouteTvIconDrawable,
+                    R.attr.mediaRouteSpeakerIconDrawable,
+                    R.attr.mediaRouteSpeakerGroupIconDrawable});
+            mDefaultIcon = styledAttributes.getDrawable(0);
+            mBluetoothIcon = styledAttributes.getDrawable(1);
+            mTvIcon = styledAttributes.getDrawable(2);
+            mSpeakerIcon = styledAttributes.getDrawable(3);
+            mSpeakerGroupIcon = styledAttributes.getDrawable(4);
+            styledAttributes.recycle();
         }
 
         @Override
@@ -209,21 +246,32 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             View view = convertView;
             if (view == null) {
-                view = mInflater.inflate(R.layout.mr_media_route_list_item, parent, false);
+                view = mInflater.inflate(R.layout.mr_chooser_list_item, parent, false);
             }
+
             MediaRouter.RouteInfo route = getItem(position);
-            TextView text1 = (TextView)view.findViewById(android.R.id.text1);
-            TextView text2 = (TextView)view.findViewById(android.R.id.text2);
+            TextView text1 = (TextView) view.findViewById(R.id.mr_chooser_route_name);
+            TextView text2 = (TextView) view.findViewById(R.id.mr_chooser_route_desc);
             text1.setText(route.getName());
             String description = route.getDescription();
-            if (TextUtils.isEmpty(description)) {
-                text2.setVisibility(View.GONE);
-                text2.setText("");
-            } else {
+            boolean isConnectedOrConnecting =
+                    route.getConnectionState() == CONNECTION_STATE_CONNECTED
+                            || route.getConnectionState() == CONNECTION_STATE_CONNECTING;
+            if (isConnectedOrConnecting && !TextUtils.isEmpty(description)) {
+                text1.setGravity(Gravity.BOTTOM);
                 text2.setVisibility(View.VISIBLE);
                 text2.setText(description);
+            } else {
+                text1.setGravity(Gravity.CENTER_VERTICAL);
+                text2.setVisibility(View.GONE);
+                text2.setText("");
             }
             view.setEnabled(route.isEnabled());
+
+            ImageView iconView = (ImageView) view.findViewById(R.id.mr_chooser_route_icon);
+            if (iconView != null) {
+                iconView.setImageDrawable(getIconDrawable(route));
+            }
             return view;
         }
 
@@ -232,9 +280,49 @@
             MediaRouter.RouteInfo route = getItem(position);
             if (route.isEnabled()) {
                 route.select();
+                RouteComparator.storeRouteUsageScores(getContext(), route.getId());
                 dismiss();
             }
         }
+
+        private Drawable getIconDrawable(MediaRouter.RouteInfo route) {
+            Uri iconUri = route.getIconUri();
+            if (iconUri != null) {
+                try {
+                    InputStream is = getContext().getContentResolver().openInputStream(iconUri);
+                    Drawable drawable = Drawable.createFromStream(is, null);
+                    if (drawable != null) {
+                        return drawable;
+                    }
+                } catch (IOException e) {
+                    Log.w(TAG, "Failed to load " + iconUri, e);
+                    // Falls back.
+                }
+            }
+            return getDefaultIconDrawable(route);
+        }
+
+        private Drawable getDefaultIconDrawable(MediaRouter.RouteInfo route) {
+            // If the type of the receiver device is specified, use it.
+            switch (route.getDeviceType()) {
+                case MediaRouter.RouteInfo.DEVICE_TYPE_BLUETOOTH:
+                    return mBluetoothIcon;
+                case  MediaRouter.RouteInfo.DEVICE_TYPE_TV:
+                    return mTvIcon;
+                case MediaRouter.RouteInfo.DEVICE_TYPE_SPEAKER:
+                    return mSpeakerIcon;
+            }
+
+            // Otherwise, make the best guess based on other route information.
+            if (route instanceof MediaRouter.RouteGroup) {
+                // Only speakers can be grouped for now.
+                return mSpeakerGroupIcon;
+            }
+            if (route.isDeviceTypeBluetooth()) {
+                return mBluetoothIcon;
+            }
+            return mDefaultIcon;
+        }
     }
 
     private final class MediaRouterCallback extends MediaRouter.Callback {
@@ -260,11 +348,87 @@
     }
 
     private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> {
+        private static final String PREF_ROUTE_IDS =
+                "android.support.v7.app.MediaRouteChooserDialog_route_ids";
+        private static final String PREF_USAGE_SCORE_PREFIX =
+                "android.support.v7.app.MediaRouteChooserDialog_route_usage_score_";
+        // Routes with the usage score less than MIN_USAGE_SCORE are decayed.
+        private static final float MIN_USAGE_SCORE = 0.1f;
+        private static final float USAGE_SCORE_DECAY_FACTOR = 0.95f;
+
         public static final RouteComparator sInstance = new RouteComparator();
+        public static final HashMap<String, Float> sRouteUsageScoreMap = new HashMap();
 
         @Override
         public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
+            if (lhs == null) {
+                return rhs == null ? 0 : -1;
+            } else if (rhs == null) {
+                return 1;
+            }
+            if (lhs.isDeviceTypeBluetooth()) {
+                if (!rhs.isDeviceTypeBluetooth()) {
+                    return 1;
+                }
+            } else if (rhs.isDeviceTypeBluetooth()) {
+                return -1;
+            }
+            Float lhsUsageScore = sRouteUsageScoreMap.get(lhs.getId());
+            if (lhsUsageScore == null) {
+                lhsUsageScore = 0f;
+            }
+            Float rhsUsageScore = sRouteUsageScoreMap.get(rhs.getId());
+            if (rhsUsageScore == null) {
+                rhsUsageScore = 0f;
+            }
+            if (!lhsUsageScore.equals(rhsUsageScore)) {
+                return lhsUsageScore > rhsUsageScore ? -1 : 1;
+            }
             return lhs.getName().compareTo(rhs.getName());
         }
+
+        private static void loadRouteUsageScores(
+                Context context, List<MediaRouter.RouteInfo> routes) {
+            sRouteUsageScoreMap.clear();
+            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+            for (MediaRouter.RouteInfo route : routes) {
+                sRouteUsageScoreMap.put(route.getId(),
+                        preferences.getFloat(PREF_USAGE_SCORE_PREFIX + route.getId(), 0f));
+            }
+        }
+
+        private static void storeRouteUsageScores(Context context, String selectedRouteId) {
+            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+            SharedPreferences.Editor prefEditor = preferences.edit();
+            List<String> routeIds = new ArrayList<String>(
+                    Arrays.asList(preferences.getString(PREF_ROUTE_IDS, "").split(",")));
+            if (!routeIds.contains(selectedRouteId)) {
+                routeIds.add(selectedRouteId);
+            }
+            StringBuilder routeIdsBuilder = new StringBuilder();
+            for (String routeId : routeIds) {
+                // The new route usage score is calculated as follows:
+                // 1) usageScore * USAGE_SCORE_DECAY_FACTOR + 1, if the route is selected,
+                // 2) 0, if usageScore * USAGE_SCORE_DECAY_FACTOR < MIN_USAGE_SCORE, or
+                // 3) usageScore * USAGE_SCORE_DECAY_FACTOR, otherwise,
+                String routeUsageScoreKey = PREF_USAGE_SCORE_PREFIX + routeId;
+                float newUsageScore = preferences.getFloat(routeUsageScoreKey, 0f)
+                        * USAGE_SCORE_DECAY_FACTOR;
+                if (selectedRouteId.equals(routeId)) {
+                    newUsageScore += 1f;
+                }
+                if (newUsageScore < MIN_USAGE_SCORE) {
+                    prefEditor.remove(routeId);
+                } else {
+                    prefEditor.putFloat(routeUsageScoreKey, newUsageScore);
+                    if (routeIdsBuilder.length() > 0) {
+                        routeIdsBuilder.append(',');
+                    }
+                    routeIdsBuilder.append(routeId);
+                }
+            }
+            prefEditor.putString(PREF_ROUTE_IDS, routeIdsBuilder.toString());
+            prefEditor.commit();
+        }
     }
 }
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
index 3b5239a..835b613 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
@@ -18,6 +18,7 @@
 
 import android.app.Dialog;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.support.v4.app.DialogFragment;
 import android.support.v7.media.MediaRouteSelector;
@@ -32,6 +33,7 @@
 public class MediaRouteChooserDialogFragment extends DialogFragment {
     private final String ARGUMENT_SELECTOR = "selector";
 
+    private MediaRouteChooserDialog mDialog;
     private MediaRouteSelector mSelector;
 
     /**
@@ -108,8 +110,16 @@
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
-        MediaRouteChooserDialog dialog = onCreateChooserDialog(getActivity(), savedInstanceState);
-        dialog.setRouteSelector(getRouteSelector());
-        return dialog;
+        mDialog = onCreateChooserDialog(getActivity(), savedInstanceState);
+        mDialog.setRouteSelector(getRouteSelector());
+        return mDialog;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (mDialog != null) {
+            mDialog.updateLayout();
+        }
     }
 }
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index f98e6b2..1f375a0 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -16,9 +16,16 @@
 
 package android.support.v7.app;
 
+import android.app.PendingIntent;
+import android.content.ContentResolver;
 import android.content.Context;
-import android.content.IntentSender;
-import android.graphics.drawable.Drawable;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.support.v4.media.MediaDescriptionCompat;
@@ -26,21 +33,40 @@
 import android.support.v4.media.session.MediaControllerCompat;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.media.session.PlaybackStateCompat;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
+import android.support.v7.graphics.Palette;
 import android.support.v7.media.MediaRouteSelector;
 import android.support.v7.media.MediaRouter;
 import android.support.v7.mediarouter.R;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
 import android.widget.SeekBar;
 import android.widget.TextView;
 
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * This class implements the route controller dialog for {@link MediaRouter}.
  * <p>
@@ -56,53 +82,87 @@
     // Time to wait before updating the volume when the user lets go of the seek bar
     // to allow the route provider time to propagate the change and publish a new
     // route descriptor.
-    private static final int VOLUME_UPDATE_DELAY_MILLIS = 250;
+    private static final int VOLUME_UPDATE_DELAY_MILLIS = 500;
+
+    private static final int BUTTON_NEUTRAL_RES_ID = android.R.id.button3;
+    private static final int BUTTON_DISCONNECT_RES_ID = android.R.id.button2;
+    private static final int BUTTON_STOP_RES_ID = android.R.id.button1;
 
     private final MediaRouter mRouter;
     private final MediaRouterCallback mCallback;
     private final MediaRouter.RouteInfo mRoute;
 
+    private Context mContext;
     private boolean mCreated;
     private boolean mAttachedToWindow;
-    private Drawable mMediaRouteConnectingDrawable;
-    private Drawable mMediaRouteOnDrawable;
 
-    private View mControlView;
+    private int mDialogContentWidth;
+
+    private View mCustomControlView;
 
     private Button mDisconnectButton;
     private Button mStopCastingButton;
     private ImageButton mPlayPauseButton;
-    private ImageButton mSettingsButton;
+    private ImageButton mCloseButton;
+    private MediaRouteExpandCollapseButton mGroupExpandCollapseButton;
 
+    private FrameLayout mExpandableAreaLayout;
+    private LinearLayout mDialogAreaLayout;
+    private FrameLayout mDefaultControlLayout;
+    private FrameLayout mCustomControlLayout;
     private ImageView mArtView;
     private TextView mTitleView;
     private TextView mSubtitleView;
-    private TextView mRouteNameView;
+    private TextView mRouteNameTextView;
 
     private boolean mVolumeControlEnabled = true;
-    private LinearLayout mVolumeLayout;
+    // Layout for media controllers including play/pause button and the main volume slider.
+    private LinearLayout mMediaMainControlLayout;
+    private RelativeLayout mPlaybackControlLayout;
+    private LinearLayout mVolumeControlLayout;
+    private View mDividerView;
+
+    private ListView mVolumeGroupList;
     private SeekBar mVolumeSlider;
-    private boolean mVolumeSliderTouched;
+    private VolumeChangeListener mVolumeChangeListener;
+    private MediaRouter.RouteInfo mRouteInVolumeSliderTouched;
+    private int mVolumeGroupListItemIconSize;
+    private int mVolumeGroupListItemHeight;
+    private int mVolumeGroupListMaxHeight;
+    private final int mVolumeGroupListPaddingTop;
+    private Map<MediaRouter.RouteInfo, SeekBar> mVolumeSliderMap;
 
     private MediaControllerCompat mMediaController;
     private MediaControllerCallback mControllerCallback;
     private PlaybackStateCompat mState;
     private MediaDescriptionCompat mDescription;
 
+    private FetchArtTask mFetchArtTask;
+    private Bitmap mArtIconBitmap;
+    private Uri mArtIconUri;
+    private boolean mIsGroupExpanded;
+    private boolean mIsGroupListAnimationNeeded;
+    private int mGroupListAnimationDurationMs;
+
+    private final AccessibilityManager mAccessibilityManager;
 
     public MediaRouteControllerDialog(Context context) {
         this(context, 0);
     }
 
     public MediaRouteControllerDialog(Context context, int theme) {
-        super(MediaRouterThemeHelper.createThemedContext(context), theme);
-        context = getContext();
+        super(MediaRouterThemeHelper.createThemedContext(context, theme), theme);
+        mContext = getContext();
 
         mControllerCallback = new MediaControllerCallback();
-        mRouter = MediaRouter.getInstance(context);
+        mRouter = MediaRouter.getInstance(mContext);
         mCallback = new MediaRouterCallback();
         mRoute = mRouter.getSelectedRoute();
         setMediaSession(mRouter.getMediaSessionToken());
+        mVolumeGroupListPaddingTop = mContext.getResources().getDimensionPixelSize(
+                R.dimen.mr_controller_volume_group_list_padding_top);
+        mAccessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
     }
 
     /**
@@ -112,10 +172,16 @@
         return mRoute;
     }
 
+    private MediaRouter.RouteGroup getGroup() {
+        if (mRoute instanceof MediaRouter.RouteGroup) {
+            return (MediaRouter.RouteGroup) mRoute;
+        }
+        return null;
+    }
+
     /**
-     * Provides the subclass an opportunity to create a view that will
-     * be included within the body of the dialog to offer additional media controls
-     * for the currently playing content.
+     * Provides the subclass an opportunity to create a view that will replace the default media
+     * controls for the currently playing content.
      *
      * @param savedInstanceState The dialog's saved instance state.
      * @return The media control view, or null if none.
@@ -130,7 +196,7 @@
      * @return The media control view, or null if none.
      */
     public View getMediaControlView() {
-        return mControlView;
+        return mCustomControlView;
     }
 
     /**
@@ -144,7 +210,7 @@
         if (mVolumeControlEnabled != enable) {
             mVolumeControlEnabled = enable;
             if (mCreated) {
-                updateVolume();
+                updateVolumeControlLayout();
             }
         }
     }
@@ -176,7 +242,7 @@
             return;
         }
         try {
-            mMediaController = new MediaControllerCompat(getContext(), sessionToken);
+            mMediaController = new MediaControllerCompat(mContext, sessionToken);
         } catch (RemoteException e) {
             Log.e(TAG, "Error creating media controller in setMediaSession.", e);
         }
@@ -191,9 +257,9 @@
     }
 
     /**
-     * Gets the description being used by the default UI.
+     * Gets the session to use for metadata and transport controls.
      *
-     * @return The current description.
+     * @return The token for the session to use or null if none.
      */
     public MediaSessionCompat.Token getMediaSession() {
         return mMediaController == null ? null : mMediaController.getSessionToken();
@@ -203,73 +269,142 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        setContentView(R.layout.mr_media_route_controller_material_dialog_b);
+        getWindow().setBackgroundDrawableResource(android.R.color.transparent);
+        setContentView(R.layout.mr_controller_material_dialog_b);
+
+        // Remove the neutral button.
+        findViewById(BUTTON_NEUTRAL_RES_ID).setVisibility(View.GONE);
 
         ClickListener listener = new ClickListener();
 
-        mDisconnectButton = (Button) findViewById(R.id.disconnect);
-        mDisconnectButton.setOnClickListener(listener);
-
-        mStopCastingButton = (Button) findViewById(R.id.stop);
-        mStopCastingButton.setOnClickListener(listener);
-
-        mSettingsButton = (ImageButton) findViewById(R.id.settings);
-        mSettingsButton.setOnClickListener(listener);
-
-        mArtView = (ImageView) findViewById(R.id.art);
-        mTitleView = (TextView) findViewById(R.id.title);
-        mSubtitleView = (TextView) findViewById(R.id.subtitle);
-        mPlayPauseButton = (ImageButton) findViewById(R.id.play_pause);
-        mPlayPauseButton.setOnClickListener(listener);
-        mRouteNameView = (TextView) findViewById(R.id.route_name);
-        mVolumeLayout = (LinearLayout)findViewById(R.id.media_route_volume_layout);
-        mVolumeSlider = (SeekBar)findViewById(R.id.media_route_volume_slider);
-        mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-            private final Runnable mStopTrackingTouch = new Runnable() {
-                @Override
-                public void run() {
-                    if (mVolumeSliderTouched) {
-                        mVolumeSliderTouched = false;
-                        updateVolume();
-                    }
-                }
-            };
-
+        mExpandableAreaLayout = (FrameLayout) findViewById(R.id.mr_expandable_area);
+        mExpandableAreaLayout.setOnClickListener(new View.OnClickListener() {
             @Override
-            public void onStartTrackingTouch(SeekBar seekBar) {
-                if (mVolumeSliderTouched) {
-                    mVolumeSlider.removeCallbacks(mStopTrackingTouch);
-                } else {
-                    mVolumeSliderTouched = true;
-                }
-            }
-
-            @Override
-            public void onStopTrackingTouch(SeekBar seekBar) {
-                // Defer resetting mVolumeSliderTouched to allow the media route provider
-                // a little time to settle into its new state and publish the final
-                // volume update.
-                mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS);
-            }
-
-            @Override
-            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                if (fromUser) {
-                    mRoute.requestSetVolume(progress);
-                }
+            public void onClick(View v) {
+                dismiss();
             }
         });
-
-        mCreated = true;
-        if (update()) {
-            mControlView = onCreateMediaControlView(savedInstanceState);
-            FrameLayout controlFrame =
-                    (FrameLayout)findViewById(R.id.media_route_control_frame);
-            if (mControlView != null) {
-                controlFrame.findViewById(R.id.default_control_frame).setVisibility(View.GONE);
-                controlFrame.addView(mControlView);
+        mDialogAreaLayout = (LinearLayout) findViewById(R.id.mr_dialog_area);
+        mDialogAreaLayout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // Eat unhandled touch events.
             }
+        });
+        int color = MediaRouterThemeHelper.getButtonTextColor(mContext);
+        mDisconnectButton = (Button) findViewById(BUTTON_DISCONNECT_RES_ID);
+        mDisconnectButton.setText(R.string.mr_controller_disconnect);
+        mDisconnectButton.setTextColor(color);
+        mDisconnectButton.setOnClickListener(listener);
+
+        mStopCastingButton = (Button) findViewById(BUTTON_STOP_RES_ID);
+        mStopCastingButton.setText(R.string.mr_controller_stop);
+        mStopCastingButton.setTextColor(color);
+        mStopCastingButton.setOnClickListener(listener);
+
+        mRouteNameTextView = (TextView) findViewById(R.id.mr_name);
+        mCloseButton = (ImageButton) findViewById(R.id.mr_close);
+        mCloseButton.setOnClickListener(listener);
+        mCustomControlLayout = (FrameLayout) findViewById(R.id.mr_custom_control);
+        mDefaultControlLayout = (FrameLayout) findViewById(R.id.mr_default_control);
+
+        // Start the session activity when a content item (album art, title or subtitle) is clicked.
+        View.OnClickListener onClickListener = new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mMediaController != null) {
+                    PendingIntent pi = mMediaController.getSessionActivity();
+                    if (pi != null) {
+                        try {
+                            pi.send();
+                            dismiss();
+                        } catch (PendingIntent.CanceledException e) {
+                            Log.e(TAG, pi + " was not sent, it had been canceled.");
+                        }
+                    }
+                }
+            }
+        };
+        mArtView = (ImageView) findViewById(R.id.mr_art);
+        mArtView.setOnClickListener(onClickListener);
+        findViewById(R.id.mr_control_title_container).setOnClickListener(onClickListener);
+
+        mMediaMainControlLayout = (LinearLayout) findViewById(R.id.mr_media_main_control);
+        mDividerView = findViewById(R.id.mr_control_divider);
+
+        mPlaybackControlLayout = (RelativeLayout) findViewById(R.id.mr_playback_control);
+        mTitleView = (TextView) findViewById(R.id.mr_control_title);
+        mSubtitleView = (TextView) findViewById(R.id.mr_control_subtitle);
+        mPlayPauseButton = (ImageButton) findViewById(R.id.mr_control_play_pause);
+        mPlayPauseButton.setOnClickListener(listener);
+
+        mVolumeControlLayout = (LinearLayout) findViewById(R.id.mr_volume_control);
+        mVolumeControlLayout.setVisibility(View.GONE);
+        mVolumeSlider = (SeekBar) findViewById(R.id.mr_volume_slider);
+        mVolumeSlider.setTag(mRoute);
+        mVolumeChangeListener = new VolumeChangeListener();
+        mVolumeSlider.setOnSeekBarChangeListener(mVolumeChangeListener);
+
+        mVolumeGroupList = (ListView) findViewById(R.id.mr_volume_group_list);
+        MediaRouterThemeHelper.setMediaControlsBackgroundColor(mContext,
+                mMediaMainControlLayout, mVolumeGroupList, getGroup() != null);
+        MediaRouterThemeHelper.setVolumeSliderColor(mContext,
+                (MediaRouteVolumeSlider) mVolumeSlider, mMediaMainControlLayout);
+        mVolumeSliderMap = new HashMap<>();
+        mVolumeSliderMap.put(mRoute, mVolumeSlider);
+
+        mGroupExpandCollapseButton =
+                (MediaRouteExpandCollapseButton) findViewById(R.id.mr_group_expand_collapse);
+        mGroupExpandCollapseButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mIsGroupExpanded = !mIsGroupExpanded;
+                if (mIsGroupExpanded) {
+                    mVolumeGroupList.setVisibility(View.VISIBLE);
+                    mVolumeGroupList.setAdapter(
+                            new VolumeGroupAdapter(mContext, getGroup().getRoutes()));
+                } else {
+                    // Request layout to update UI based on {@code mIsGroupExpanded}.
+                    mDefaultControlLayout.requestLayout();
+                }
+                mIsGroupListAnimationNeeded = true;
+                updateLayoutHeight();
+            }
+        });
+        mGroupListAnimationDurationMs = mContext.getResources().getInteger(
+                R.integer.mr_controller_volume_group_list_animation_duration_ms);
+
+        mCustomControlView = onCreateMediaControlView(savedInstanceState);
+        if (mCustomControlView != null) {
+            mCustomControlLayout.addView(mCustomControlView);
+            mCustomControlLayout.setVisibility(View.VISIBLE);
         }
+        mCreated = true;
+        updateLayout();
+    }
+
+    /**
+     * Sets the width of the dialog. Also called when configuration changes.
+     */
+    void updateLayout() {
+        int width = MediaRouteDialogHelper.getDialogWidth(mContext);
+        getWindow().setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+        View decorView = getWindow().getDecorView();
+        mDialogContentWidth = width - decorView.getPaddingLeft() - decorView.getPaddingRight();
+
+        Resources res = mContext.getResources();
+        mVolumeGroupListItemIconSize = res.getDimensionPixelSize(
+                R.dimen.mr_controller_volume_group_list_item_icon_size);
+        mVolumeGroupListItemHeight = res.getDimensionPixelSize(
+                R.dimen.mr_controller_volume_group_list_item_height);
+        mVolumeGroupListMaxHeight = res.getDimensionPixelSize(
+                R.dimen.mr_controller_volume_group_list_max_height);
+
+        // Ensure the mArtView is updated.
+        mArtIconBitmap = null;
+        mArtIconUri = null;
+        update();
     }
 
     @Override
@@ -309,122 +444,331 @@
         return super.onKeyUp(keyCode, event);
     }
 
-    private boolean update() {
+    private void update() {
         if (!mRoute.isSelected() || mRoute.isDefault()) {
             dismiss();
-            return false;
+            return;
         }
         if (!mCreated) {
-            return false;
+            return;
         }
 
-        updateVolume();
+        mRouteNameTextView.setText(mRoute.getName());
+        mDisconnectButton.setVisibility(mRoute.canDisconnect() ? View.VISIBLE : View.GONE);
 
-        mRouteNameView.setText(mRoute.getName());
+        if (mCustomControlView == null) {
+            if (mFetchArtTask != null) {
+                mFetchArtTask.cancel(true);
+            }
+            mFetchArtTask = new FetchArtTask();
+            mFetchArtTask.execute();
+        }
+        updateVolumeControlLayout();
+        updatePlaybackControlLayout();
+    }
 
-        if (mRoute.canDisconnect()) {
-            mDisconnectButton.setVisibility(View.VISIBLE);
+    private boolean canShowPlaybackControlLayout() {
+        return mCustomControlView == null && (mDescription != null || mState != null);
+    }
+
+    /**
+     * Returns the height of main media controller which includes playback control and master
+     * volume control.
+     */
+    private int getMainControllerHeight(boolean showPlaybackControl) {
+        int height = 0;
+        if (showPlaybackControl || mVolumeControlLayout.getVisibility() == View.VISIBLE) {
+            height += mMediaMainControlLayout.getPaddingTop()
+                    + mMediaMainControlLayout.getPaddingBottom();
+            if (showPlaybackControl) {
+                height +=  mPlaybackControlLayout.getMeasuredHeight();
+            }
+            if (mVolumeControlLayout.getVisibility() == View.VISIBLE) {
+                height += mVolumeControlLayout.getMeasuredHeight();
+            }
+            if (showPlaybackControl && mVolumeControlLayout.getVisibility() == View.VISIBLE) {
+                height += mDividerView.getMeasuredHeight();
+            }
+        }
+        return height;
+    }
+
+    private void updateMediaControlVisibility(boolean canShowPlaybackControlLayout) {
+        // TODO: Update the top and bottom padding of the control layout according to the display
+        // height.
+        mDividerView.setVisibility((mVolumeControlLayout.getVisibility() == View.VISIBLE
+                && canShowPlaybackControlLayout) ? View.VISIBLE : View.GONE);
+        mMediaMainControlLayout.setVisibility((mVolumeControlLayout.getVisibility() == View.GONE
+                && !canShowPlaybackControlLayout) ? View.GONE : View.VISIBLE);
+    }
+
+    private void updateLayoutHeight() {
+        // We need to defer the update until the first layout has occurred, as we don't yet know the
+        // overall visible display size in which the window this view is attached to has been
+        // positioned in.
+        ViewTreeObserver observer = mDefaultControlLayout.getViewTreeObserver();
+        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+            @Override
+            public void onGlobalLayout() {
+                mDefaultControlLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+                updateLayoutHeightInternal();
+            }
+        });
+    }
+
+    /**
+     * Updates the height of views and hide artwork or metadata if space is limited.
+     */
+    private void updateLayoutHeightInternal() {
+        // Measure the size of widgets and get the height of main components.
+        int oldHeight = getLayoutHeight(mMediaMainControlLayout);
+        setLayoutHeight(mMediaMainControlLayout, ViewGroup.LayoutParams.FILL_PARENT);
+        updateMediaControlVisibility(canShowPlaybackControlLayout());
+        View decorView = getWindow().getDecorView();
+        decorView.measure(
+                MeasureSpec.makeMeasureSpec(getWindow().getAttributes().width, MeasureSpec.EXACTLY),
+                MeasureSpec.UNSPECIFIED);
+        setLayoutHeight(mMediaMainControlLayout, oldHeight);
+        int artViewHeight = 0;
+        if (mCustomControlView == null && mArtView.getDrawable() instanceof BitmapDrawable) {
+            Bitmap art = ((BitmapDrawable) mArtView.getDrawable()).getBitmap();
+            if (art != null) {
+                artViewHeight = getDesiredArtHeight(art.getWidth(), art.getHeight());
+                mArtView.setScaleType(art.getWidth() >= art.getHeight()
+                        ? ImageView.ScaleType.FIT_XY : ImageView.ScaleType.FIT_CENTER);
+            }
+        }
+        int mainControllerHeight = getMainControllerHeight(canShowPlaybackControlLayout());
+        int volumeGroupListCount = mVolumeGroupList.getAdapter() != null
+                ? mVolumeGroupList.getAdapter().getCount() : 0;
+        // Scale down volume group list items in landscape mode.
+        for (int i = 0; i < mVolumeGroupList.getChildCount(); i++) {
+            updateVolumeGroupItemHeight(mVolumeGroupList.getChildAt(i));
+        }
+        int expandedGroupListHeight = mVolumeGroupListItemHeight * volumeGroupListCount;
+        if (volumeGroupListCount > 0) {
+            expandedGroupListHeight += mVolumeGroupListPaddingTop;
+        }
+        expandedGroupListHeight = Math.min(expandedGroupListHeight, mVolumeGroupListMaxHeight);
+        int visibleGroupListHeight = mIsGroupExpanded ? expandedGroupListHeight : 0;
+
+        int desiredControlLayoutHeight =
+                Math.max(artViewHeight, visibleGroupListHeight) + mainControllerHeight;
+        Rect visibleRect = new Rect();
+        decorView.getWindowVisibleDisplayFrame(visibleRect);
+        // Height of non-control views in decor view.
+        // This includes title bar, button bar, and dialog's vertical padding which should be
+        // always shown.
+        int nonControlViewHeight = mDialogAreaLayout.getMeasuredHeight()
+                - mDefaultControlLayout.getMeasuredHeight();
+        // Maximum allowed height for controls to fit screen.
+        int maximumControlViewHeight = visibleRect.height() - nonControlViewHeight;
+
+        // Show artwork if it fits the screen.
+        if (mCustomControlView == null && artViewHeight > 0
+                && desiredControlLayoutHeight <= maximumControlViewHeight) {
+            mArtView.setVisibility(View.VISIBLE);
+            setLayoutHeight(mArtView, artViewHeight);
         } else {
-            mDisconnectButton.setVisibility(View.GONE);
-        }
-
-        if (mRoute.getSettingsIntent() != null) {
-            mSettingsButton.setVisibility(View.VISIBLE);
-        } else {
-            mSettingsButton.setVisibility(View.GONE);
-        }
-
-        if (mControlView == null) {
-            if (mDescription != null && mDescription.getIconBitmap() != null) {
-                mArtView.setImageBitmap(mDescription.getIconBitmap());
-                mArtView.setVisibility(View.VISIBLE);
-            } else if (mDescription != null && mDescription.getIconUri() != null) {
-                // TODO replace with background load of icon
-                mArtView.setImageURI(mDescription.getIconUri());
-                mArtView.setVisibility(View.VISIBLE);
-            } else {
-                mArtView.setImageDrawable(null);
+            if (getLayoutHeight(mVolumeGroupList) + mMediaMainControlLayout.getMeasuredHeight()
+                    >= mDefaultControlLayout.getMeasuredHeight()) {
                 mArtView.setVisibility(View.GONE);
             }
+            artViewHeight = 0;
+            desiredControlLayoutHeight = visibleGroupListHeight + mainControllerHeight;
+        }
+        // Show the playback control if it fits the screen.
+        if (canShowPlaybackControlLayout()
+                && desiredControlLayoutHeight <= maximumControlViewHeight) {
+            mPlaybackControlLayout.setVisibility(View.VISIBLE);
+        } else {
+            mPlaybackControlLayout.setVisibility(View.GONE);
+        }
+        updateMediaControlVisibility(mPlaybackControlLayout.getVisibility() == View.VISIBLE);
+        mainControllerHeight = getMainControllerHeight(
+                mPlaybackControlLayout.getVisibility() == View.VISIBLE);
+        desiredControlLayoutHeight =
+                Math.max(artViewHeight, visibleGroupListHeight) + mainControllerHeight;
 
+        // Limit the volume group list height to fit the screen.
+        if (desiredControlLayoutHeight > maximumControlViewHeight) {
+            visibleGroupListHeight -= (desiredControlLayoutHeight - maximumControlViewHeight);
+            desiredControlLayoutHeight = maximumControlViewHeight;
+        }
+        // Update the layouts with the computed heights.
+        mMediaMainControlLayout.clearAnimation();
+        mVolumeGroupList.clearAnimation();
+        mDefaultControlLayout.clearAnimation();
+        if (mIsGroupListAnimationNeeded) {
+            animateLayoutHeight(mMediaMainControlLayout, mainControllerHeight);
+            animateLayoutHeight(mVolumeGroupList, visibleGroupListHeight);
+            animateLayoutHeight(mDefaultControlLayout, desiredControlLayoutHeight);
+        } else {
+            setLayoutHeight(mMediaMainControlLayout, mainControllerHeight);
+            setLayoutHeight(mVolumeGroupList, visibleGroupListHeight);
+            setLayoutHeight(mDefaultControlLayout, desiredControlLayoutHeight);
+        }
+        mIsGroupListAnimationNeeded = false;
+        // Maximize the window size with a transparent layout in advance for smooth animation.
+        setLayoutHeight(mExpandableAreaLayout, visibleRect.height());
+    }
+
+    private void updateVolumeGroupItemHeight(View item) {
+        setLayoutHeight(item, mVolumeGroupListItemHeight);
+        View icon = item.findViewById(R.id.mr_volume_item_icon);
+        ViewGroup.LayoutParams lp = icon.getLayoutParams();
+        lp.width = mVolumeGroupListItemIconSize;
+        lp.height = mVolumeGroupListItemIconSize;
+        icon.setLayoutParams(lp);
+    }
+
+    private void animateLayoutHeight(final View view, int targetHeight) {
+        final int startValue = getLayoutHeight(view);
+        final int endValue = targetHeight;
+        Animation anim = new Animation() {
+            @Override
+            protected void applyTransformation(float interpolatedTime, Transformation t) {
+                int height = startValue - (int) ((startValue - endValue) * interpolatedTime);
+                setLayoutHeight(view, height);
+            }
+        };
+        anim.setDuration(mGroupListAnimationDurationMs);
+        if (android.os.Build.VERSION.SDK_INT >= 21) {
+            anim.setInterpolator(mContext, mIsGroupExpanded ? R.interpolator.mr_linear_out_slow_in
+                    : R.interpolator.mr_fast_out_slow_in);
+        }
+        if (view == mVolumeGroupList) {
+            anim.setAnimationListener(new Animation.AnimationListener() {
+                @Override
+                public void onAnimationStart(Animation animation) {
+                    mVolumeGroupList.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
+                }
+
+                @Override
+                public void onAnimationEnd(Animation animation) {
+                    mVolumeGroupList.setTranscriptMode(ListView.TRANSCRIPT_MODE_DISABLED);
+                }
+
+                @Override
+                public void onAnimationRepeat(Animation animation) { }
+            });
+        }
+        view.startAnimation(anim);
+    }
+
+    private void updateVolumeControlLayout() {
+        if (isVolumeControlAvailable(mRoute)) {
+            if (mVolumeControlLayout.getVisibility() == View.GONE) {
+                mVolumeControlLayout.setVisibility(View.VISIBLE);
+                mVolumeSlider.setMax(mRoute.getVolumeMax());
+                mVolumeSlider.setProgress(mRoute.getVolume());
+                if (getGroup() == null) {
+                    mGroupExpandCollapseButton.setVisibility(View.GONE);
+                } else {
+                    mGroupExpandCollapseButton.setVisibility(View.VISIBLE);
+                    VolumeGroupAdapter adapter =
+                            (VolumeGroupAdapter) mVolumeGroupList.getAdapter();
+                    if (adapter != null) {
+                        adapter.notifyDataSetChanged();
+                    }
+                }
+            }
+        } else {
+            mVolumeControlLayout.setVisibility(View.GONE);
+        }
+        updateLayoutHeight();
+    }
+
+    private void updatePlaybackControlLayout() {
+        if (canShowPlaybackControlLayout()) {
             CharSequence title = mDescription == null ? null : mDescription.getTitle();
             boolean hasTitle = !TextUtils.isEmpty(title);
 
             CharSequence subtitle = mDescription == null ? null : mDescription.getSubtitle();
             boolean hasSubtitle = !TextUtils.isEmpty(subtitle);
 
-            if (!hasTitle && !hasSubtitle) {
-                mTitleView.setText(R.string.mr_media_route_controller_no_info_available);
-                mTitleView.setEnabled(false);
-                mTitleView.setVisibility(View.VISIBLE);
-                mSubtitleView.setVisibility(View.GONE);
+            boolean showTitle = false;
+            boolean showSubtitle = false;
+            if (mRoute.getPresentationDisplayId()
+                    != MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE) {
+                // The user is currently casting screen.
+                mTitleView.setText(R.string.mr_controller_casting_screen);
+                showTitle = true;
+            } else if (mState == null || mState.getState() == PlaybackStateCompat.STATE_NONE) {
+                // Show "No media selected" as we don't yet know the playback state.
+                // (Only exception is bluetooth where we don't show anything.)
+                if (!mRoute.isDeviceTypeBluetooth()) {
+                    mTitleView.setText(R.string.mr_controller_no_media_selected);
+                    showTitle = true;
+                }
+            } else if (!hasTitle && !hasSubtitle) {
+                mTitleView.setText(R.string.mr_controller_no_info_available);
+                showTitle = true;
             } else {
-                mTitleView.setText(title);
-                mTitleView.setEnabled(hasTitle);
-                mTitleView.setVisibility(hasTitle ? View.VISIBLE : View.GONE);
-                mSubtitleView.setText(subtitle);
-                mSubtitleView.setVisibility(hasSubtitle ? View.VISIBLE : View.GONE);
+                if (hasTitle) {
+                    mTitleView.setText(title);
+                    showTitle = true;
+                }
+                if (hasSubtitle) {
+                    mSubtitleView.setText(subtitle);
+                    showSubtitle = true;
+                }
             }
+            mTitleView.setVisibility(showTitle ? View.VISIBLE : View.GONE);
+            mSubtitleView.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
+
             if (mState != null) {
                 boolean isPlaying = mState.getState() == PlaybackStateCompat.STATE_BUFFERING
                         || mState.getState() == PlaybackStateCompat.STATE_PLAYING;
                 boolean supportsPlay = (mState.getActions() & (PlaybackStateCompat.ACTION_PLAY
                         | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
                 boolean supportsPause = (mState.getActions() & (PlaybackStateCompat.ACTION_PAUSE
-                                | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
+                        | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
                 if (isPlaying && supportsPause) {
                     mPlayPauseButton.setVisibility(View.VISIBLE);
                     mPlayPauseButton.setImageResource(MediaRouterThemeHelper.getThemeResource(
-                            getContext(), R.attr.mediaRoutePauseDrawable));
-                    mPlayPauseButton.setContentDescription(getContext().getResources()
-                            .getText(R.string.mr_media_route_controller_pause));
+                            mContext, R.attr.mediaRoutePauseDrawable));
+                    mPlayPauseButton.setContentDescription(mContext.getResources()
+                            .getText(R.string.mr_controller_pause));
                 } else if (!isPlaying && supportsPlay) {
                     mPlayPauseButton.setVisibility(View.VISIBLE);
                     mPlayPauseButton.setImageResource(MediaRouterThemeHelper.getThemeResource(
-                            getContext(), R.attr.mediaRoutePlayDrawable));
-                    mPlayPauseButton.setContentDescription(getContext().getResources()
-                            .getText(R.string.mr_media_route_controller_play));
+                            mContext, R.attr.mediaRoutePlayDrawable));
+                    mPlayPauseButton.setContentDescription(mContext.getResources()
+                            .getText(R.string.mr_controller_play));
                 } else {
                     mPlayPauseButton.setVisibility(View.GONE);
                 }
-            } else {
-                mPlayPauseButton.setVisibility(View.GONE);
             }
         }
-        return true;
+        updateLayoutHeight();
     }
 
-    private Drawable getIconDrawable() {
-        if (mRoute.isConnecting()) {
-            if (mMediaRouteConnectingDrawable == null) {
-                mMediaRouteConnectingDrawable = MediaRouterThemeHelper.getThemeDrawable(
-                        getContext(), R.attr.mediaRouteConnectingDrawable);
-            }
-            return mMediaRouteConnectingDrawable;
-        } else {
-            if (mMediaRouteOnDrawable == null) {
-                mMediaRouteOnDrawable = MediaRouterThemeHelper.getThemeDrawable(
-                        getContext(), R.attr.mediaRouteOnDrawable);
-            }
-            return mMediaRouteOnDrawable;
+    private boolean isVolumeControlAvailable(MediaRouter.RouteInfo route) {
+        return mVolumeControlEnabled && route.getVolumeHandling()
+                == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+    }
+
+    private static int getLayoutHeight(View view) {
+        return view.getLayoutParams().height;
+    }
+
+    private static void setLayoutHeight(View view, int height) {
+        ViewGroup.LayoutParams lp = view.getLayoutParams();
+        lp.height = height;
+        view.setLayoutParams(lp);
+    }
+
+    /**
+     * Returns desired art height to fit into controller dialog.
+     */
+    private int getDesiredArtHeight(int originalWidth, int originalHeight) {
+        if (originalWidth >= originalHeight) {
+            // For landscape art, fit width to dialog width.
+            return (int) ((float) mDialogContentWidth * originalHeight / originalWidth + 0.5f);
         }
-    }
-
-    private void updateVolume() {
-        if (!mVolumeSliderTouched) {
-            if (isVolumeControlAvailable()) {
-                mVolumeLayout.setVisibility(View.VISIBLE);
-                mVolumeSlider.setMax(mRoute.getVolumeMax());
-                mVolumeSlider.setProgress(mRoute.getVolume());
-            } else {
-                mVolumeLayout.setVisibility(View.GONE);
-            }
-        }
-    }
-
-    private boolean isVolumeControlAvailable() {
-        return mVolumeControlEnabled && mRoute.getVolumeHandling() ==
-                MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+        // For portrait art, fit height to 16:9 ratio case's height.
+        return (int) ((float) mDialogContentWidth * 9 / 16 + 0.5f);
     }
 
     private final class MediaRouterCallback extends MediaRouter.Callback {
@@ -440,8 +784,9 @@
 
         @Override
         public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) {
-            if (route == mRoute) {
-                updateVolume();
+            SeekBar volumeSlider = mVolumeSliderMap.get(route);
+            if (volumeSlider != null && mRouteInVolumeSliderTouched != route) {
+                volumeSlider.setProgress(route.getVolume());
             }
         }
     }
@@ -472,31 +817,228 @@
         @Override
         public void onClick(View v) {
             int id = v.getId();
-            if (id == R.id.stop || id == R.id.disconnect) {
+            if (id == BUTTON_STOP_RES_ID || id == BUTTON_DISCONNECT_RES_ID) {
                 if (mRoute.isSelected()) {
-                    mRouter.unselect(id == R.id.stop ?
+                    mRouter.unselect(id == BUTTON_STOP_RES_ID ?
                             MediaRouter.UNSELECT_REASON_STOPPED :
                             MediaRouter.UNSELECT_REASON_DISCONNECTED);
                 }
                 dismiss();
-            } else if (id == R.id.play_pause) {
+            } else if (id == R.id.mr_control_play_pause) {
                 if (mMediaController != null && mState != null) {
-                    if (mState.getState() == PlaybackStateCompat.STATE_PLAYING) {
+                    boolean isPlaying = mState.getState() == PlaybackStateCompat.STATE_PLAYING;
+                    if (isPlaying) {
                         mMediaController.getTransportControls().pause();
                     } else {
                         mMediaController.getTransportControls().play();
                     }
-                }
-            } else if (id == R.id.settings) {
-                IntentSender is = mRoute.getSettingsIntent();
-                if (is != null) {
-                    try {
-                        is.sendIntent(null, 0, null, null, null);
-                        dismiss();
-                    } catch (Exception e) {
-                        Log.e(TAG, "Error opening route settings.", e);
+                    // Announce the action for accessibility.
+                    if (mAccessibilityManager != null && mAccessibilityManager.isEnabled()) {
+                        AccessibilityEvent event = AccessibilityEvent.obtain(
+                                AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
+                        event.setPackageName(mContext.getPackageName());
+                        event.setClassName(getClass().getName());
+                        int resId = isPlaying ?
+                                R.string.mr_controller_pause : R.string.mr_controller_play;
+                        event.getText().add(mContext.getString(resId));
+                        mAccessibilityManager.sendAccessibilityEvent(event);
                     }
                 }
+            } else if (id == R.id.mr_close) {
+                dismiss();
+            }
+        }
+    }
+
+    private class VolumeChangeListener implements SeekBar.OnSeekBarChangeListener {
+        private final Runnable mStopTrackingTouch = new Runnable() {
+            @Override
+            public void run() {
+                if (mRouteInVolumeSliderTouched != null) {
+                    SeekBar volumeSlider = mVolumeSliderMap.get(mRouteInVolumeSliderTouched);
+                    volumeSlider.setProgress(mRouteInVolumeSliderTouched.getVolume());
+                    mRouteInVolumeSliderTouched = null;
+                }
+            }
+        };
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+            if (mRouteInVolumeSliderTouched != null) {
+                mVolumeSlider.removeCallbacks(mStopTrackingTouch);
+            }
+            mRouteInVolumeSliderTouched = (MediaRouter.RouteInfo) seekBar.getTag();
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            // Defer resetting mVolumeSliderTouched to allow the media route provider
+            // a little time to settle into its new state and publish the final
+            // volume update.
+            mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS);
+        }
+
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+            if (fromUser) {
+                MediaRouter.RouteInfo route = (MediaRouter.RouteInfo) seekBar.getTag();
+                if (route.getVolume() != progress) {
+                    route.requestSetVolume(progress);
+                }
+            }
+        }
+    }
+
+    private class VolumeGroupAdapter extends ArrayAdapter<MediaRouter.RouteInfo> {
+        final float mDisabledAlpha;
+
+        public VolumeGroupAdapter(Context context, List<MediaRouter.RouteInfo> objects) {
+            super(context, 0, objects);
+            mDisabledAlpha = MediaRouterThemeHelper.getDisabledAlpha(context);
+        }
+
+        @Override
+        public View getView(final int position, View convertView, ViewGroup parent) {
+            View v = convertView;
+            if (v == null) {
+                v = LayoutInflater.from(mContext).inflate(
+                        R.layout.mr_controller_volume_item, parent, false);
+            } else {
+                updateVolumeGroupItemHeight(v);
+            }
+
+            MediaRouter.RouteInfo route = getItem(position);
+            if (route != null) {
+                boolean isEnabled = route.isEnabled();
+
+                TextView routeName = (TextView) v.findViewById(R.id.mr_name);
+                routeName.setEnabled(isEnabled);
+                routeName.setText(route.getName());
+
+                MediaRouteVolumeSlider volumeSlider =
+                        (MediaRouteVolumeSlider) v.findViewById(R.id.mr_volume_slider);
+                MediaRouterThemeHelper.setVolumeSliderColor(
+                        mContext, volumeSlider, mVolumeGroupList);
+                volumeSlider.setTag(route);
+                mVolumeSliderMap.put(route, volumeSlider);
+                volumeSlider.setHideThumb(!isEnabled);
+                volumeSlider.setEnabled(isEnabled);
+                if (isEnabled) {
+                    if (isVolumeControlAvailable(route)) {
+                        volumeSlider.setMax(route.getVolumeMax());
+                        volumeSlider.setProgress(route.getVolume());
+                        volumeSlider.setOnSeekBarChangeListener(mVolumeChangeListener);
+                    } else {
+                        volumeSlider.setMax(100);
+                        volumeSlider.setProgress(100);
+                        volumeSlider.setEnabled(false);
+                    }
+                }
+
+                ImageView volumeItemIcon =
+                        (ImageView) v.findViewById(R.id.mr_volume_item_icon);
+                volumeItemIcon.setAlpha(isEnabled ? 0xFF : (int) (0xFF * mDisabledAlpha));
+            }
+            return v;
+        }
+    }
+
+    private class FetchArtTask extends AsyncTask<Void, Void, Bitmap> {
+        final Bitmap mIconBitmap;
+        final Uri mIconUri;
+        int mBackgroundColor;
+
+        FetchArtTask() {
+            mIconBitmap = mDescription == null ? null : mDescription.getIconBitmap();
+            mIconUri = mDescription == null ? null : mDescription.getIconUri();
+        }
+
+        @Override
+        protected void onPreExecute() {
+            if (mArtIconBitmap == mIconBitmap && mArtIconUri == mIconUri) {
+                // Already handled the current art.
+                cancel(true);
+            }
+        }
+
+        @Override
+        protected Bitmap doInBackground(Void... arg) {
+            Bitmap art = null;
+            if (mIconBitmap != null) {
+                art = mIconBitmap;
+            } else if (mIconUri != null) {
+                String scheme = mIconUri.getScheme();
+                if (!(ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
+                        || ContentResolver.SCHEME_CONTENT.equals(scheme)
+                        || ContentResolver.SCHEME_FILE.equals(scheme))) {
+                    Log.w(TAG, "Icon Uri should point to local resources.");
+                    return null;
+                }
+                BufferedInputStream stream = null;
+                try {
+                    stream = new BufferedInputStream(
+                            mContext.getContentResolver().openInputStream(mIconUri));
+
+                    // Query art size.
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    options.inJustDecodeBounds = true;
+                    BitmapFactory.decodeStream(stream, null, options);
+                    if (options.outWidth == 0 || options.outHeight == 0) {
+                        return null;
+                    }
+                    // Rewind the stream in order to restart art decoding.
+                    try {
+                        stream.reset();
+                    } catch (IOException e) {
+                        // Failed to rewind the stream, try to reopen it.
+                        stream.close();
+                        stream = new BufferedInputStream(mContext.getContentResolver()
+                                .openInputStream(mIconUri));
+                    }
+                    // Calculate required size to decode the art and possibly resize it.
+                    options.inJustDecodeBounds = false;
+                    int reqHeight = getDesiredArtHeight(options.outWidth, options.outHeight);
+                    int ratio = options.outHeight / reqHeight;
+                    options.inSampleSize = Math.max(1, Integer.highestOneBit(ratio));
+                    if (isCancelled()) {
+                        return null;
+                    }
+                    art = BitmapFactory.decodeStream(stream, null, options);
+                } catch (IOException e){
+                    Log.w(TAG, "Unable to open: " + mIconUri, e);
+                } finally {
+                    if (stream != null) {
+                        try {
+                            stream.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+            }
+            if (art != null && art.getWidth() < art.getHeight()) {
+                // Portrait art requires dominant color as background color.
+                Palette palette = new Palette.Builder(art).maximumColorCount(1).generate();
+                mBackgroundColor = palette.getSwatches().isEmpty()
+                        ? 0 : palette.getSwatches().get(0).getRgb();
+            }
+            return art;
+        }
+
+        @Override
+        protected void onCancelled() {
+            mFetchArtTask = null;
+        }
+
+        @Override
+        protected void onPostExecute(Bitmap art) {
+            mFetchArtTask = null;
+            if (mArtIconBitmap != mIconBitmap || mArtIconUri != mIconUri) {
+                mArtIconBitmap = mIconBitmap;
+                mArtIconUri = mIconUri;
+
+                mArtView.setImageBitmap(art);
+                mArtView.setBackgroundColor(mBackgroundColor);
+                updateLayoutHeight();
             }
         }
     }
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java
index beb9832..6cadb9a 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java
@@ -18,6 +18,7 @@
 
 import android.app.Dialog;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.support.v4.app.DialogFragment;
 
@@ -29,6 +30,7 @@
  * </p>
  */
 public class MediaRouteControllerDialogFragment extends DialogFragment {
+    private MediaRouteControllerDialog mDialog;
     /**
      * Creates a media route controller dialog fragment.
      * <p>
@@ -52,6 +54,15 @@
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
-        return onCreateControllerDialog(getActivity(), savedInstanceState);
+        mDialog = onCreateControllerDialog(getActivity(), savedInstanceState);
+        return mDialog;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (mDialog != null) {
+            mDialog.updateLayout();
+        }
     }
 }
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java
new file mode 100644
index 0000000..99d414f
--- /dev/null
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.support.v7.mediarouter.R;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewGroup;
+
+final class MediaRouteDialogHelper {
+    /**
+     * The framework should set the dialog width properly, but somehow it doesn't work, hence
+     * duplicating a similar logic here to determine the appropriate dialog width.
+     */
+    public static int getDialogWidth(Context context) {
+        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+        boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
+
+        TypedValue value = new TypedValue();
+        context.getResources().getValue(isPortrait ? R.dimen.mr_dialog_fixed_width_minor
+                : R.dimen.mr_dialog_fixed_width_major, value, true);
+        if (value.type == TypedValue.TYPE_DIMENSION) {
+            return (int) value.getDimension(metrics);
+        } else if (value.type == TypedValue.TYPE_FRACTION) {
+            return (int) value.getFraction(metrics.widthPixels, metrics.widthPixels);
+        }
+        return ViewGroup.LayoutParams.WRAP_CONTENT;
+    }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java
new file mode 100644
index 0000000..6ccfaa8
--- /dev/null
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.AnimationDrawable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.mediarouter.R;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+
+/**
+ * Chevron/Caret button to expand/collapse group volume list with animation.
+ */
+class MediaRouteExpandCollapseButton extends ImageButton {
+    private final AnimationDrawable mExpandAnimationDrawable;
+    private final AnimationDrawable mCollapseAnimationDrawable;
+    private final String mExpandGroupDescription;
+    private final String mCollapseGroupDescription;
+    private boolean mIsGroupExpanded;
+    private OnClickListener mListener;
+
+    public MediaRouteExpandCollapseButton(Context context) {
+        this(context, null);
+    }
+
+    public MediaRouteExpandCollapseButton(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public MediaRouteExpandCollapseButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mExpandAnimationDrawable = (AnimationDrawable) ContextCompat.getDrawable(
+                context, R.drawable.ic_expand);
+        mCollapseAnimationDrawable = (AnimationDrawable) ContextCompat.getDrawable(
+                context, R.drawable.ic_collapse);
+
+        ColorFilter filter = new PorterDuffColorFilter(
+                MediaRouterThemeHelper.getControllerColor(context, defStyleAttr),
+                PorterDuff.Mode.SRC_IN);
+        mExpandAnimationDrawable.setColorFilter(filter);
+        mCollapseAnimationDrawable.setColorFilter(filter);
+
+        mExpandGroupDescription = context.getString(R.string.mr_controller_expand_group);
+        mCollapseGroupDescription = context.getString(R.string.mr_controller_collapse_group);
+
+        setImageDrawable(mExpandAnimationDrawable.getFrame(0));
+        setContentDescription(mExpandGroupDescription);
+
+        super.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                mIsGroupExpanded = !mIsGroupExpanded;
+                if (mIsGroupExpanded) {
+                    setImageDrawable(mExpandAnimationDrawable);
+                    mExpandAnimationDrawable.start();
+                    setContentDescription(mCollapseGroupDescription);
+                } else {
+                    setImageDrawable(mCollapseAnimationDrawable);
+                    mCollapseAnimationDrawable.start();
+                    setContentDescription(mExpandGroupDescription);
+                }
+                if (mListener != null) {
+                    mListener.onClick(view);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void setOnClickListener(OnClickListener listener) {
+        mListener = listener;
+    }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
new file mode 100644
index 0000000..a7aafd2
--- /dev/null
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.v7.mediarouter.R;
+import android.support.v7.widget.AppCompatSeekBar;
+import android.util.AttributeSet;
+import android.util.Log;
+
+/**
+ * Volume slider with showing, hiding, and applying alpha supports to the thumb.
+ */
+class MediaRouteVolumeSlider extends AppCompatSeekBar {
+    private static final String TAG = "MediaRouteVolumeSlider";
+
+    private final float mDisabledAlpha;
+
+    private boolean mHideThumb;
+    private Drawable mThumb;
+    private int mColor;
+
+    public MediaRouteVolumeSlider(Context context) {
+        this(context, null);
+    }
+
+    public MediaRouteVolumeSlider(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.seekBarStyle);
+    }
+
+    public MediaRouteVolumeSlider(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mDisabledAlpha = MediaRouterThemeHelper.getDisabledAlpha(context);
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        int alpha = isEnabled() ? 0xFF : (int) (0xFF * mDisabledAlpha);
+
+        // The thumb drawable is a collection of drawables and its current drawables are changed per
+        // state. Apply the color filter and alpha on every state change.
+        mThumb.setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+        mThumb.setAlpha(alpha);
+
+        getProgressDrawable().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+        getProgressDrawable().setAlpha(alpha);
+    }
+
+    @Override
+    public void setThumb(Drawable thumb) {
+        mThumb = thumb;
+        super.setThumb(mHideThumb ? null : mThumb);
+    }
+
+    /**
+     * Sets whether to show or hide thumb.
+     */
+    public void setHideThumb(boolean hideThumb) {
+        if (mHideThumb == hideThumb) {
+            return;
+        }
+        mHideThumb = hideThumb;
+        super.setThumb(mHideThumb ? null : mThumb);
+    }
+
+    /**
+     * Sets the volume slider color. The change takes effect next time drawable state is changed.
+     * <p>
+     * The color cannot be translucent, otherwise the underlying progress bar will be seen through
+     * the thumb.
+     * </p>
+     */
+    public void setColor(int color) {
+        if (mColor == color) {
+            return;
+        }
+        if (Color.alpha(color) != 0xFF) {
+            Log.e(TAG, "Volume slider color cannot be translucent: #" + Integer.toHexString(color));
+        }
+        mColor = color;
+    }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
index 09999a1..33ab7bc 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
@@ -17,19 +17,59 @@
 package android.support.v7.app;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.support.annotation.IntDef;
+import android.support.v4.graphics.ColorUtils;
 import android.support.v7.mediarouter.R;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.View;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 final class MediaRouterThemeHelper {
+    private static final float MIN_CONTRAST = 3.0f;
+
+    @IntDef({COLOR_DARK_ON_LIGHT_BACKGROUND, COLOR_WHITE_ON_DARK_BACKGROUND})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ControllerColorType {}
+
+    private static final int COLOR_DARK_ON_LIGHT_BACKGROUND = 0xDE000000; /* Opacity of 87% */
+    private static final int COLOR_WHITE_ON_DARK_BACKGROUND = Color.WHITE;
+
     private MediaRouterThemeHelper() {
     }
 
-    public static Context createThemedContext(Context context) {
-        boolean isLightTheme = isLightTheme(context);
-        return new ContextThemeWrapper(context, isLightTheme ?
-                R.style.Theme_MediaRouter_Light : R.style.Theme_MediaRouter);
+    /**
+     * Creates a themed context based on the explicit style resource or the parent context's default
+     * theme.
+     * <p>
+     * The theme which will be applied on top of the parent {@code context}'s theme is determined
+     * by the primary color defined in the given {@code style}, or in the parent {@code context}.
+     *
+     * @param context the parent context
+     * @param style the resource ID of the style against which to inflate this context, or
+     *              {@code 0} to use the parent {@code context}'s default theme.
+     * @return The themed context.
+     */
+    public static Context createThemedContext(Context context, int style) {
+        int theme;
+        if (isLightTheme(context)) {
+            if (getControllerColor(context, style) == COLOR_DARK_ON_LIGHT_BACKGROUND) {
+                theme = R.style.Theme_MediaRouter_Light;
+            } else {
+                theme = R.style.Theme_MediaRouter_Light_DarkControlPanel;
+            }
+        } else {
+            if (getControllerColor(context, style) == COLOR_DARK_ON_LIGHT_BACKGROUND) {
+                theme = R.style.Theme_MediaRouter_LightControlPanel;
+            } else {
+                theme = R.style.Theme_MediaRouter;
+            }
+        }
+        return new ContextThemeWrapper(context, theme);
     }
 
     public static int getThemeResource(Context context, int attr) {
@@ -37,9 +77,62 @@
         return context.getTheme().resolveAttribute(attr, value, true) ? value.resourceId : 0;
     }
 
-    public static Drawable getThemeDrawable(Context context, int attr) {
-        int res = getThemeResource(context, attr);
-        return res != 0 ? context.getResources().getDrawable(res) : null;
+    public static float getDisabledAlpha(Context context) {
+        TypedValue value = new TypedValue();
+        return context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, value, true)
+                ? value.getFloat() : 0.5f;
+    }
+
+    public static @ControllerColorType int getControllerColor(Context context, int style) {
+        int primaryColor = getThemeColor(context, style, R.attr.colorPrimary);
+        if (ColorUtils.calculateContrast(COLOR_WHITE_ON_DARK_BACKGROUND, primaryColor)
+                >= MIN_CONTRAST) {
+            return COLOR_WHITE_ON_DARK_BACKGROUND;
+        }
+        return COLOR_DARK_ON_LIGHT_BACKGROUND;
+    }
+
+    public static int getButtonTextColor(Context context) {
+        int primaryColor = getThemeColor(context, 0, R.attr.colorPrimary);
+        int backgroundColor = getThemeColor(context, 0, android.R.attr.colorBackground);
+
+        if (ColorUtils.calculateContrast(primaryColor, backgroundColor) < MIN_CONTRAST) {
+            // Default to colorAccent if the contrast ratio is low.
+            return getThemeColor(context, 0, R.attr.colorAccent);
+        }
+        return primaryColor;
+    }
+
+    public static void setMediaControlsBackgroundColor(
+            Context context, View mainControls, View groupControls, boolean hasGroup) {
+        int primaryColor = getThemeColor(context, 0, R.attr.colorPrimary);
+        int primaryDarkColor = getThemeColor(context, 0, R.attr.colorPrimaryDark);
+        int controllerColor = getControllerColor(context, 0);
+        if (hasGroup && controllerColor == COLOR_DARK_ON_LIGHT_BACKGROUND
+                && ColorUtils.calculateContrast(controllerColor, primaryDarkColor) < MIN_CONTRAST) {
+            // Instead of showing dark controls in a possibly dark (i.e. the primary dark), model
+            // the white dialog and use the primary color for the group controls.
+            primaryDarkColor = primaryColor;
+            primaryColor = Color.WHITE;
+        }
+        mainControls.setBackgroundColor(primaryColor);
+        groupControls.setBackgroundColor(primaryDarkColor);
+        // Also store the background colors to the view tags. They are used in
+        // setVolumeSliderColor() below.
+        mainControls.setTag(primaryColor);
+        groupControls.setTag(primaryDarkColor);
+    }
+
+    public static void setVolumeSliderColor(
+            Context context, MediaRouteVolumeSlider volumeSlider, View backgroundView) {
+        int controllerColor = getControllerColor(context, 0);
+        if (Color.alpha(controllerColor) != 0xFF) {
+            // Composite with the background in order not to show the underlying progress bar
+            // through the thumb.
+            int backgroundColor = (int) backgroundView.getTag();
+            controllerColor = ColorUtils.compositeColors(controllerColor, backgroundColor);
+        }
+        volumeSlider.setColor(controllerColor);
     }
 
     private static boolean isLightTheme(Context context) {
@@ -47,4 +140,22 @@
         return context.getTheme().resolveAttribute(R.attr.isLightTheme, value, true)
                 && value.data != 0;
     }
+
+    private static int getThemeColor(Context context, int style, int attr) {
+        if (style != 0) {
+            int[] attrs = { attr };
+            TypedArray ta = context.obtainStyledAttributes(style, attrs);
+            int color = ta.getColor(0, 0);
+            ta.recycle();
+            if (color != 0) {
+                return color;
+            }
+        }
+        TypedValue value = new TypedValue();
+        context.getTheme().resolveAttribute(attr, value, true);
+        if (value.resourceId != 0) {
+            return context.getResources().getColor(value.resourceId);
+        }
+        return value.data;
+    }
 }
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java b/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java
index d83ad2f..97a2cd7 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java
@@ -17,6 +17,7 @@
 
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.net.Uri;
 import android.os.Bundle;
 import android.text.TextUtils;
 
@@ -37,13 +38,17 @@
  */
 public final class MediaRouteDescriptor {
     private static final String KEY_ID = "id";
+    private static final String KEY_GROUP_MEMBER_IDS = "groupMemberIds";
     private static final String KEY_NAME = "name";
     private static final String KEY_DESCRIPTION = "status";
+    private static final String KEY_ICON_URI = "iconUri";
     private static final String KEY_ENABLED = "enabled";
     private static final String KEY_CONNECTING = "connecting";
+    private static final String KEY_CONNECTION_STATE = "connectionState";
     private static final String KEY_CONTROL_FILTERS = "controlFilters";
     private static final String KEY_PLAYBACK_TYPE = "playbackType";
     private static final String KEY_PLAYBACK_STREAM = "playbackStream";
+    private static final String KEY_DEVICE_TYPE = "deviceType";
     private static final String KEY_VOLUME = "volume";
     private static final String KEY_VOLUME_MAX = "volumeMax";
     private static final String KEY_VOLUME_HANDLING = "volumeHandling";
@@ -73,6 +78,18 @@
     }
 
     /**
+     * Gets the group member ids of the route.
+     * <p>
+     * A route descriptor that has one or more group member route ids
+     * represents a route group. A member route may belong to another group.
+     * </p>
+     * @hide
+     */
+    public List<String> getGroupMemberIds() {
+        return mBundle.getStringArrayList(KEY_GROUP_MEMBER_IDS);
+    }
+
+    /**
      * Gets the user-visible name of the route.
      * <p>
      * The route name identifies the destination represented by the route.
@@ -95,6 +112,17 @@
     }
 
     /**
+     * Gets the URI of the icon representing this route.
+     * <p>
+     * This icon will be used in picker UIs if available.
+     * </p>
+     */
+    public Uri getIconUri() {
+        String iconUri = mBundle.getString(KEY_ICON_URI);
+        return iconUri == null ? null : Uri.parse(iconUri);
+    }
+
+    /**
      * Gets whether the route is enabled.
      */
     public boolean isEnabled() {
@@ -103,16 +131,37 @@
 
     /**
      * Gets whether the route is connecting.
+     * @deprecated Use {@link #getConnectionState} instead
      */
     public boolean isConnecting() {
         return mBundle.getBoolean(KEY_CONNECTING, false);
     }
 
     /**
-     * Gets whether the route can be disconnected without stopping playback. To
-     * specify that the route should disconnect without stopping use
+     * Gets the connection state of the route.
+     *
+     * @return The connection state of this route:
+     * {@link MediaRouter.RouteInfo#CONNECTION_STATE_DISCONNECTED},
+     * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTING}, or
+     * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTED}.
+     */
+    public int getConnectionState() {
+        return mBundle.getInt(KEY_CONNECTION_STATE,
+                MediaRouter.RouteInfo.CONNECTION_STATE_DISCONNECTED);
+    }
+
+    /**
+     * Gets whether the route can be disconnected without stopping playback.
+     * <p>
+     * The route can normally be disconnected without stopping playback when
+     * the destination device on the route is connected to two or more source
+     * devices. The route provider should update the route immediately when the
+     * number of connected devices changes.
+     * </p><p>
+     * To specify that the route should disconnect without stopping use
      * {@link MediaRouter#unselect(int)} with
      * {@link MediaRouter#UNSELECT_REASON_DISCONNECTED}.
+     * </p>
      */
     public boolean canDisconnectAndKeepPlaying() {
         return mBundle.getBoolean(KEY_CAN_DISCONNECT, false);
@@ -147,7 +196,11 @@
     }
 
     /**
-     * Gets the route's playback type.
+     * Gets the type of playback associated with this route.
+     *
+     * @return The type of playback associated with this route:
+     * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_LOCAL} or
+     * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_REMOTE}.
      */
     public int getPlaybackType() {
         return mBundle.getInt(KEY_PLAYBACK_TYPE, MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE);
@@ -161,6 +214,17 @@
     }
 
     /**
+     * Gets the type of the receiver device associated with this route.
+     *
+     * @return The type of the receiver device associated with this route:
+     * {@link MediaRouter.RouteInfo#DEVICE_TYPE_TV} or
+     * {@link MediaRouter.RouteInfo#DEVICE_TYPE_SPEAKER}.
+     */
+    public int getDeviceType() {
+        return mBundle.getInt(KEY_DEVICE_TYPE);
+    }
+
+    /**
      * Gets the route's current volume, or 0 if unknown.
      */
     public int getVolume() {
@@ -175,7 +239,11 @@
     }
 
     /**
-     * Gets the route's volume handling.
+     * Gets information about how volume is handled on the route.
+     *
+     * @return How volume is handled on the route:
+     * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_FIXED} or
+     * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_VARIABLE}.
      */
     public int getVolumeHandling() {
         return mBundle.getInt(KEY_VOLUME_HANDLING,
@@ -186,7 +254,8 @@
      * Gets the route's presentation display id, or -1 if none.
      */
     public int getPresentationDisplayId() {
-        return mBundle.getInt(KEY_PRESENTATION_DISPLAY_ID, -1);
+        return mBundle.getInt(
+                KEY_PRESENTATION_DISPLAY_ID, MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE);
     }
 
     /**
@@ -216,13 +285,17 @@
         StringBuilder result = new StringBuilder();
         result.append("MediaRouteDescriptor{ ");
         result.append("id=").append(getId());
+        result.append(", groupMemberIds=").append(getGroupMemberIds());
         result.append(", name=").append(getName());
         result.append(", description=").append(getDescription());
+        result.append(", iconUri=").append(getIconUri());
         result.append(", isEnabled=").append(isEnabled());
         result.append(", isConnecting=").append(isConnecting());
+        result.append(", connectionState=").append(getConnectionState());
         result.append(", controlFilters=").append(Arrays.toString(getControlFilters().toArray()));
         result.append(", playbackType=").append(getPlaybackType());
         result.append(", playbackStream=").append(getPlaybackStream());
+        result.append(", deviceType=").append(getDeviceType());
         result.append(", volume=").append(getVolume());
         result.append(", volumeMax=").append(getVolumeMax());
         result.append(", volumeHandling=").append(getVolumeHandling());
@@ -257,6 +330,7 @@
      */
     public static final class Builder {
         private final Bundle mBundle;
+        private ArrayList<String> mGroupMemberIds;
         private ArrayList<IntentFilter> mControlFilters;
 
         /**
@@ -302,6 +376,49 @@
         }
 
         /**
+         * Adds a group member id of the route.
+         * <p>
+         * A route descriptor that has one or more group member route ids
+         * represents a route group. A member route may belong to another group.
+         * </p>
+         * @hide
+         */
+        public Builder addGroupMemberId(String groupMemberId) {
+            if (TextUtils.isEmpty(groupMemberId)) {
+                throw new IllegalArgumentException("groupMemberId must not be empty");
+            }
+
+            if (mGroupMemberIds == null) {
+                mGroupMemberIds = new ArrayList<>();
+            }
+            if (!mGroupMemberIds.contains(groupMemberId)) {
+                mGroupMemberIds.add(groupMemberId);
+            }
+            return this;
+        }
+
+        /**
+         * Adds a list of group member ids of the route.
+         * <p>
+         * A route descriptor that has one or more group member route ids
+         * represents a route group. A member route may belong to another group.
+         * </p>
+         * @hide
+         */
+        public Builder addGroupMemberIds(Collection<String> groupMemberIds) {
+            if (groupMemberIds == null) {
+                throw new IllegalArgumentException("groupMemberIds must not be null");
+            }
+
+            if (!groupMemberIds.isEmpty()) {
+                for (String groupMemberId : groupMemberIds) {
+                    addGroupMemberId(groupMemberId);
+                }
+            }
+            return this;
+        }
+
+        /**
          * Sets the user-visible name of the route.
          * <p>
          * The route name identifies the destination represented by the route.
@@ -326,6 +443,28 @@
         }
 
         /**
+         * Sets the URI of the icon representing this route.
+         * <p>
+         * This icon will be used in picker UIs if available.
+         * </p><p>
+         * The URI must be one of the following formats:
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         * </p>
+         */
+        public Builder setIconUri(Uri iconUri) {
+            if (iconUri == null) {
+                throw new IllegalArgumentException("iconUri must not be null");
+            }
+            mBundle.putString(KEY_ICON_URI, iconUri.toString());
+            return this;
+        }
+
+        /**
          * Sets whether the route is enabled.
          * <p>
          * Disabled routes represent routes that a route provider knows about, such as paired
@@ -340,6 +479,7 @@
         /**
          * Sets whether the route is in the process of connecting and is not yet
          * ready for use.
+         * @deprecated Use {@link #setConnectionState} instead.
          */
         public Builder setConnecting(boolean connecting) {
             mBundle.putBoolean(KEY_CONNECTING, connecting);
@@ -347,6 +487,19 @@
         }
 
         /**
+         * Sets the route's connection state.
+         *
+         * @param connectionState The connection state of the route:
+         * {@link MediaRouter.RouteInfo#CONNECTION_STATE_DISCONNECTED},
+         * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTING}, or
+         * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTED}.
+         */
+        public Builder setConnectionState(int connectionState) {
+            mBundle.putInt(KEY_CONNECTION_STATE, connectionState);
+            return this;
+        }
+
+        /**
          * Sets whether the route can be disconnected without stopping playback.
          */
         public Builder setCanDisconnect(boolean canDisconnect) {
@@ -398,6 +551,10 @@
 
         /**
          * Sets the route's playback type.
+         *
+         * @param playbackType The playback type of the route:
+         * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_LOCAL} or
+         * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_REMOTE}.
          */
         public Builder setPlaybackType(int playbackType) {
             mBundle.putInt(KEY_PLAYBACK_TYPE, playbackType);
@@ -413,6 +570,18 @@
         }
 
         /**
+         * Sets the route's receiver device type.
+         *
+         * @param deviceType The receive device type of the route:
+         * {@link MediaRouter.RouteInfo#DEVICE_TYPE_TV} or
+         * {@link MediaRouter.RouteInfo#DEVICE_TYPE_SPEAKER}.
+         */
+        public Builder setDeviceType(int deviceType) {
+            mBundle.putInt(KEY_DEVICE_TYPE, deviceType);
+            return this;
+        }
+
+        /**
          * Sets the route's current volume, or 0 if unknown.
          */
         public Builder setVolume(int volume) {
@@ -430,6 +599,10 @@
 
         /**
          * Sets the route's volume handling.
+         *
+         * @param volumeHandling how volume is handled on the route:
+         * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_FIXED} or
+         * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_VARIABLE}.
          */
         public Builder setVolumeHandling(int volumeHandling) {
             mBundle.putInt(KEY_VOLUME_HANDLING, volumeHandling);
@@ -461,6 +634,9 @@
             if (mControlFilters != null) {
                 mBundle.putParcelableArrayList(KEY_CONTROL_FILTERS, mControlFilters);
             }
+            if (mGroupMemberIds != null) {
+                mBundle.putStringArrayList(KEY_GROUP_MEMBER_IDS, mGroupMemberIds);
+            }
             return new MediaRouteDescriptor(mBundle, mControlFilters);
         }
     }
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index d37ed95..b2e74e4 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -17,7 +17,6 @@
 package android.support.v7.media;
 
 import android.app.ActivityManager;
-import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -26,6 +25,7 @@
 import android.content.IntentSender;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -37,7 +37,10 @@
 import android.support.v4.hardware.display.DisplayManagerCompat;
 import android.support.v4.media.VolumeProviderCompat;
 import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.util.Pair;
 import android.support.v7.media.MediaRouteProvider.ProviderMetadata;
+import android.support.v7.media.MediaRouteProvider.RouteController;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
 
@@ -46,8 +49,10 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 /**
  * MediaRouter allows applications to control the routing of media channels
@@ -762,26 +767,57 @@
      * route and the manner in which it is used and controlled.
      * </p>
      */
-    public static final class RouteInfo {
+    public static class RouteInfo {
         private final ProviderInfo mProvider;
         private final String mDescriptorId;
         private final String mUniqueId;
         private String mName;
         private String mDescription;
+        private Uri mIconUri;
         private boolean mEnabled;
         private boolean mConnecting;
+        private int mConnectionState;
         private boolean mCanDisconnect;
-        private final ArrayList<IntentFilter> mControlFilters = new ArrayList<IntentFilter>();
+        private final ArrayList<IntentFilter> mControlFilters = new ArrayList<>();
         private int mPlaybackType;
         private int mPlaybackStream;
+        private int mDeviceType;
         private int mVolumeHandling;
         private int mVolume;
         private int mVolumeMax;
         private Display mPresentationDisplay;
-        private int mPresentationDisplayId = -1;
+        private int mPresentationDisplayId = PRESENTATION_DISPLAY_ID_NONE;
         private Bundle mExtras;
         private IntentSender mSettingsIntent;
-        private MediaRouteDescriptor mDescriptor;
+        MediaRouteDescriptor mDescriptor;
+
+        /** @hide */
+        @IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
+                CONNECTION_STATE_CONNECTED})
+        @Retention(RetentionPolicy.SOURCE)
+        private @interface ConnectionState {}
+
+        /**
+         * The default connection state indicating the route is disconnected.
+         *
+         * @see #getConnectionState
+         */
+        public static final int CONNECTION_STATE_DISCONNECTED = 0;
+
+        /**
+         * A connection state indicating the route is in the process of connecting and is not yet
+         * ready for use.
+         *
+         * @see #getConnectionState
+         */
+        public static final int CONNECTION_STATE_CONNECTING = 1;
+
+        /**
+         * A connection state indicating the route is connected.
+         *
+         * @see #getConnectionState
+         */
+        public static final int CONNECTION_STATE_CONNECTED = 2;
 
         /** @hide */
         @IntDef({PLAYBACK_TYPE_LOCAL,PLAYBACK_TYPE_REMOTE})
@@ -806,6 +842,45 @@
         public static final int PLAYBACK_TYPE_REMOTE = 1;
 
         /** @hide */
+        @IntDef({DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV, DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH})
+        @Retention(RetentionPolicy.SOURCE)
+        private @interface DeviceType {}
+
+        /**
+         * The default receiver device type of the route indicating the type is unknown.
+         *
+         * @see #getDeviceType
+         * @hide
+         */
+        public static final int DEVICE_TYPE_UNKNOWN = 0;
+
+
+        /**
+         * A receiver device type of the route indicating the presentation of the media is happening
+         * on a bluetooth device such as a bluetooth speaker.
+         *
+         * @see #getDeviceType
+         * @hide
+         */
+        public static final int DEVICE_TYPE_BLUETOOTH = -1;
+
+        /**
+         * A receiver device type of the route indicating the presentation of the media is happening
+         * on a TV.
+         *
+         * @see #getDeviceType
+         */
+        public static final int DEVICE_TYPE_TV = 1;
+
+        /**
+         * A receiver device type of the route indicating the presentation of the media is happening
+         * on a speaker.
+         *
+         * @see #getDeviceType
+         */
+        public static final int DEVICE_TYPE_SPEAKER = 2;
+
+        /** @hide */
         @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE})
         @Retention(RetentionPolicy.SOURCE)
         private @interface PlaybackVolume {}
@@ -828,10 +903,20 @@
          */
         public static final int PLAYBACK_VOLUME_VARIABLE = 1;
 
+        /**
+         * The default presentation display id indicating no presentation display is associated
+         * with the route.
+         * @hide
+         */
+        public static final int PRESENTATION_DISPLAY_ID_NONE = -1;
+
         static final int CHANGE_GENERAL = 1 << 0;
         static final int CHANGE_VOLUME = 1 << 1;
         static final int CHANGE_PRESENTATION_DISPLAY = 1 << 2;
 
+        // Should match to SystemMediaRouteProvider.PACKAGE_NAME.
+        static final String SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME = "android";
+
         RouteInfo(ProviderInfo provider, String descriptorId, String uniqueId) {
             mProvider = provider;
             mDescriptorId = descriptorId;
@@ -889,6 +974,18 @@
         }
 
         /**
+         * Gets the URI of the icon representing this route.
+         * <p>
+         * This icon will be used in picker UIs if available.
+         * </p>
+         *
+         * @return The URI of the icon representing this route, or null if none.
+         */
+        public Uri getIconUri() {
+            return mIconUri;
+        }
+
+        /**
          * Returns true if this route is enabled and may be selected.
          *
          * @return True if this route is enabled.
@@ -908,6 +1005,17 @@
         }
 
         /**
+         * Gets the connection state of the route.
+         *
+         * @return The connection state of this route: {@link #CONNECTION_STATE_DISCONNECTED},
+         * {@link #CONNECTION_STATE_CONNECTING}, or {@link #CONNECTION_STATE_CONNECTED}.
+         */
+        @ConnectionState
+        public int getConnectionState() {
+            return mConnectionState;
+        }
+
+        /**
          * Returns true if this route is currently selected.
          *
          * @return True if this route is currently selected.
@@ -1113,6 +1221,43 @@
         }
 
         /**
+         * Gets the type of the receiver device associated with this route.
+         *
+         * @return The type of the receiver device associated with this route:
+         * {@link #DEVICE_TYPE_TV} or {@link #DEVICE_TYPE_SPEAKER}.
+         */
+        public int getDeviceType() {
+            return mDeviceType;
+        }
+
+
+        /**
+         * Gets whether the type of the receiver device associated with this route is
+         * {@link #DEVICE_TYPE_BLUETOOTH}.
+         * <p>
+         * This is a workaround for platform version 23 or below where the system route provider
+         * doesn't specify device type for bluetooth media routes.
+         * </p>
+         *
+         * @return True if the receiver device type can be assumed to be
+         *         {@link #DEVICE_TYPE_BLUETOOTH}, false otherwise.
+         * @hide
+         */
+        public boolean isDeviceTypeBluetooth() {
+            if (mDeviceType == DEVICE_TYPE_BLUETOOTH) {
+                return true;
+            }
+            return isSystemMediaRouteProvider(this)
+                    && supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
+                    && !supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO);
+        }
+
+        private static boolean isSystemMediaRouteProvider(MediaRouter.RouteInfo route) {
+            return TextUtils.equals(route.getProviderInstance().getMetadata().getPackageName(),
+                    SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME);
+        }
+
+        /**
          * Gets information about how volume is handled on the route.
          *
          * @return How volume is handled on the route: {@link #PLAYBACK_VOLUME_FIXED}
@@ -1223,6 +1368,14 @@
         }
 
         /**
+         * Gets the route's presentation display id, or -1 if none.
+         * @hide
+         */
+        public int getPresentationDisplayId() {
+            return mPresentationDisplayId;
+        }
+
+        /**
          * Gets a collection of extra properties about this route that were supplied
          * by its media route provider, or null if none.
          */
@@ -1253,11 +1406,14 @@
             return "MediaRouter.RouteInfo{ uniqueId=" + mUniqueId
                     + ", name=" + mName
                     + ", description=" + mDescription
+                    + ", iconUri=" + mIconUri
                     + ", enabled=" + mEnabled
                     + ", connecting=" + mConnecting
+                    + ", connectionState=" + mConnectionState
                     + ", canDisconnect=" + mCanDisconnect
                     + ", playbackType=" + mPlaybackType
                     + ", playbackStream=" + mPlaybackStream
+                    + ", deviceType=" + mDeviceType
                     + ", volumeHandling=" + mVolumeHandling
                     + ", volume=" + mVolume
                     + ", volumeMax=" + mVolumeMax
@@ -1268,69 +1424,87 @@
                     + " }";
         }
 
-        int updateDescriptor(MediaRouteDescriptor descriptor) {
+        int maybeUpdateDescriptor(MediaRouteDescriptor descriptor) {
             int changes = 0;
             if (mDescriptor != descriptor) {
-                mDescriptor = descriptor;
-                if (descriptor != null) {
-                    if (!equal(mName, descriptor.getName())) {
-                        mName = descriptor.getName();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (!equal(mDescription, descriptor.getDescription())) {
-                        mDescription = descriptor.getDescription();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (mEnabled != descriptor.isEnabled()) {
-                        mEnabled = descriptor.isEnabled();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (mConnecting != descriptor.isConnecting()) {
-                        mConnecting = descriptor.isConnecting();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (!mControlFilters.equals(descriptor.getControlFilters())) {
-                        mControlFilters.clear();
-                        mControlFilters.addAll(descriptor.getControlFilters());
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (mPlaybackType != descriptor.getPlaybackType()) {
-                        mPlaybackType = descriptor.getPlaybackType();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (mPlaybackStream != descriptor.getPlaybackStream()) {
-                        mPlaybackStream = descriptor.getPlaybackStream();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (mVolumeHandling != descriptor.getVolumeHandling()) {
-                        mVolumeHandling = descriptor.getVolumeHandling();
-                        changes |= CHANGE_GENERAL | CHANGE_VOLUME;
-                    }
-                    if (mVolume != descriptor.getVolume()) {
-                        mVolume = descriptor.getVolume();
-                        changes |= CHANGE_GENERAL | CHANGE_VOLUME;
-                    }
-                    if (mVolumeMax != descriptor.getVolumeMax()) {
-                        mVolumeMax = descriptor.getVolumeMax();
-                        changes |= CHANGE_GENERAL | CHANGE_VOLUME;
-                    }
-                    if (mPresentationDisplayId != descriptor.getPresentationDisplayId()) {
-                        mPresentationDisplayId = descriptor.getPresentationDisplayId();
-                        mPresentationDisplay = null;
-                        changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
-                    }
-                    if (!equal(mExtras, descriptor.getExtras())) {
-                        mExtras = descriptor.getExtras();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (!equal(mSettingsIntent, descriptor.getSettingsActivity())) {
-                        mSettingsIntent = descriptor.getSettingsActivity();
-                        changes |= CHANGE_GENERAL;
-                    }
-                    if (mCanDisconnect != descriptor.canDisconnectAndKeepPlaying()) {
-                        mCanDisconnect = descriptor.canDisconnectAndKeepPlaying();
-                        changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
-                    }
+                changes = updateDescriptor(descriptor);
+            }
+            return changes;
+        }
+
+        int updateDescriptor(MediaRouteDescriptor descriptor) {
+            int changes = 0;
+            mDescriptor = descriptor;
+            if (descriptor != null) {
+                if (!equal(mName, descriptor.getName())) {
+                    mName = descriptor.getName();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (!equal(mDescription, descriptor.getDescription())) {
+                    mDescription = descriptor.getDescription();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (!equal(mIconUri, descriptor.getIconUri())) {
+                    mIconUri = descriptor.getIconUri();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mEnabled != descriptor.isEnabled()) {
+                    mEnabled = descriptor.isEnabled();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mConnecting != descriptor.isConnecting()) {
+                    mConnecting = descriptor.isConnecting();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mConnectionState != descriptor.getConnectionState()) {
+                    mConnectionState = descriptor.getConnectionState();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (!mControlFilters.equals(descriptor.getControlFilters())) {
+                    mControlFilters.clear();
+                    mControlFilters.addAll(descriptor.getControlFilters());
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mPlaybackType != descriptor.getPlaybackType()) {
+                    mPlaybackType = descriptor.getPlaybackType();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mPlaybackStream != descriptor.getPlaybackStream()) {
+                    mPlaybackStream = descriptor.getPlaybackStream();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mDeviceType != descriptor.getDeviceType()) {
+                    mDeviceType = descriptor.getDeviceType();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mVolumeHandling != descriptor.getVolumeHandling()) {
+                    mVolumeHandling = descriptor.getVolumeHandling();
+                    changes |= CHANGE_GENERAL | CHANGE_VOLUME;
+                }
+                if (mVolume != descriptor.getVolume()) {
+                    mVolume = descriptor.getVolume();
+                    changes |= CHANGE_GENERAL | CHANGE_VOLUME;
+                }
+                if (mVolumeMax != descriptor.getVolumeMax()) {
+                    mVolumeMax = descriptor.getVolumeMax();
+                    changes |= CHANGE_GENERAL | CHANGE_VOLUME;
+                }
+                if (mPresentationDisplayId != descriptor.getPresentationDisplayId()) {
+                    mPresentationDisplayId = descriptor.getPresentationDisplayId();
+                    mPresentationDisplay = null;
+                    changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
+                }
+                if (!equal(mExtras, descriptor.getExtras())) {
+                    mExtras = descriptor.getExtras();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (!equal(mSettingsIntent, descriptor.getSettingsActivity())) {
+                    mSettingsIntent = descriptor.getSettingsActivity();
+                    changes |= CHANGE_GENERAL;
+                }
+                if (mCanDisconnect != descriptor.canDisconnectAndKeepPlaying()) {
+                    mCanDisconnect = descriptor.canDisconnectAndKeepPlaying();
+                    changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
                 }
             }
             return changes;
@@ -1340,12 +1514,91 @@
             return mDescriptorId;
         }
 
-        MediaRouteProvider getProviderInstance() {
+        /** @hide */
+        public MediaRouteProvider getProviderInstance() {
             return mProvider.getProviderInstance();
         }
     }
 
     /**
+     * Information about a route that consists of multiple other routes in a group.
+     * @hide
+     */
+    public static class RouteGroup extends RouteInfo {
+        private List<RouteInfo> mRoutes = new ArrayList<>();
+
+        RouteGroup(ProviderInfo provider, String descriptorId, String uniqueId) {
+            super(provider, descriptorId, uniqueId);
+        }
+
+        /**
+         * @return The number of routes in this group
+         */
+        public int getRouteCount() {
+            return mRoutes.size();
+        }
+
+        /**
+         * Returns the route in this group at the specified index
+         *
+         * @param index Index to fetch
+         * @return The route at index
+         */
+        public RouteInfo getRouteAt(int index) {
+            return mRoutes.get(index);
+        }
+
+        /**
+         * Returns the routes in this group
+         *
+         * @return The list of the routes in this group
+         */
+        public List<RouteInfo> getRoutes() {
+            return mRoutes;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(super.toString());
+            sb.append('[');
+            final int count = mRoutes.size();
+            for (int i = 0; i < count; i++) {
+                if (i > 0) sb.append(", ");
+                sb.append(mRoutes.get(i));
+            }
+            sb.append(']');
+            return sb.toString();
+        }
+
+        @Override
+        int maybeUpdateDescriptor(MediaRouteDescriptor descriptor) {
+            boolean changed = false;
+            if (mDescriptor != descriptor) {
+                mDescriptor = descriptor;
+                if (descriptor != null) {
+                    List<String> groupMemberIds = descriptor.getGroupMemberIds();
+                    List<RouteInfo> routes = new ArrayList<>();
+                    changed = groupMemberIds.size() != mRoutes.size();
+                    for (String groupMemberId : groupMemberIds) {
+                        String uniqueId = sGlobal.getUniqueId(getProvider(), groupMemberId);
+                        RouteInfo groupMember = sGlobal.getRoute(uniqueId);
+                        if (groupMember != null) {
+                            routes.add(groupMember);
+                            if (!changed && !mRoutes.contains(groupMember)) {
+                                changed = true;
+                            }
+                        }
+                    }
+                    if (changed) {
+                        mRoutes = routes;
+                    }
+                }
+            }
+            return (changed ? CHANGE_GENERAL : 0) | super.updateDescriptor(descriptor);
+        }
+    }
+
+    /**
      * Provides information about a media route provider.
      * <p>
      * This object may be used to determine which media route provider has
@@ -1354,7 +1607,7 @@
      */
     public static final class ProviderInfo {
         private final MediaRouteProvider mProviderInstance;
-        private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+        private final List<RouteInfo> mRoutes = new ArrayList<>();
 
         private final ProviderMetadata mMetadata;
         private MediaRouteProviderDescriptor mDescriptor;
@@ -1602,13 +1855,12 @@
             implements SystemMediaRouteProvider.SyncCallback,
             RegisteredMediaRouteProviderWatcher.Callback {
         private final Context mApplicationContext;
-        private final ArrayList<WeakReference<MediaRouter>> mRouters =
-                new ArrayList<WeakReference<MediaRouter>>();
-        private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
-        private final ArrayList<ProviderInfo> mProviders =
-                new ArrayList<ProviderInfo>();
+        private final ArrayList<WeakReference<MediaRouter>> mRouters = new ArrayList<>();
+        private final ArrayList<RouteInfo> mRoutes = new ArrayList<>();
+        private final Map<Pair<String, String>, String> mUniqueIdMap = new HashMap<>();
+        private final ArrayList<ProviderInfo> mProviders = new ArrayList<>();
         private final ArrayList<RemoteControlClientRecord> mRemoteControlClients =
-                new ArrayList<RemoteControlClientRecord>();
+                new ArrayList<>();
         private final RemoteControlClientCompat.PlaybackInfo mPlaybackInfo =
                 new RemoteControlClientCompat.PlaybackInfo();
         private final ProviderCallback mProviderCallback = new ProviderCallback();
@@ -1620,7 +1872,8 @@
         private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher;
         private RouteInfo mDefaultRoute;
         private RouteInfo mSelectedRoute;
-        private MediaRouteProvider.RouteController mSelectedRouteController;
+        private RouteController mSelectedRouteController;
+        private Map<String, RouteController> mGroupMemberControllers;
         private MediaRouteDiscoveryRequest mDiscoveryRequest;
         private MediaSessionRecord mMediaSession;
         private MediaSessionCompat mRccMediaSession;
@@ -1711,6 +1964,11 @@
         public void requestSetVolume(RouteInfo route, int volume) {
             if (route == mSelectedRoute && mSelectedRouteController != null) {
                 mSelectedRouteController.onSetVolume(volume);
+            } else if (mGroupMemberControllers != null) {
+                RouteController controller = mGroupMemberControllers.get(route.mDescriptorId);
+                if (controller != null) {
+                    controller.onSetVolume(volume);
+                }
             }
         }
 
@@ -1720,6 +1978,15 @@
             }
         }
 
+        public RouteInfo getRoute(String uniqueId) {
+            for (RouteInfo info : mRoutes) {
+                if (info.mUniqueId.equals(uniqueId)) {
+                    return info;
+                }
+            }
+            return null;
+        }
+
         public List<RouteInfo> getRoutes() {
             return mRoutes;
         }
@@ -1930,6 +2197,11 @@
                         final List<MediaRouteDescriptor> routeDescriptors =
                                 providerDescriptor.getRoutes();
                         final int routeCount = routeDescriptors.size();
+                        // Updating route group's contents requires all member routes' information.
+                        // Add the groups to the lists and update them later.
+                        List<Pair<RouteInfo, MediaRouteDescriptor>> addedGroups = new ArrayList<>();
+                        List<Pair<RouteInfo, MediaRouteDescriptor>> updatedGroups =
+                                new ArrayList<>();
                         for (int i = 0; i < routeCount; i++) {
                             final MediaRouteDescriptor routeDescriptor = routeDescriptors.get(i);
                             final String id = routeDescriptor.getId();
@@ -1937,16 +2209,23 @@
                             if (sourceIndex < 0) {
                                 // 1. Add the route to the list.
                                 String uniqueId = assignRouteUniqueId(provider, id);
-                                RouteInfo route = new RouteInfo(provider, id, uniqueId);
+                                boolean isGroup = routeDescriptor.getGroupMemberIds() != null;
+                                RouteInfo route = isGroup ? new RouteGroup(provider, id, uniqueId) :
+                                        new RouteInfo(provider, id, uniqueId);
                                 provider.mRoutes.add(targetIndex++, route);
                                 mRoutes.add(route);
                                 // 2. Create the route's contents.
-                                route.updateDescriptor(routeDescriptor);
-                                // 3. Notify clients about addition.
-                                if (DEBUG) {
-                                    Log.d(TAG, "Route added: " + route);
+                                if (isGroup) {
+                                    addedGroups.add(new Pair(route, routeDescriptor));
+                                } else {
+                                    route.maybeUpdateDescriptor(routeDescriptor);
+                                    // 3. Notify clients about addition.
+                                    if (DEBUG) {
+                                        Log.d(TAG, "Route added: " + route);
+                                    }
+                                    mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route);
                                 }
-                                mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route);
+
                             } else if (sourceIndex < targetIndex) {
                                 Log.w(TAG, "Ignoring route descriptor with duplicate id: "
                                         + routeDescriptor);
@@ -1956,34 +2235,33 @@
                                 Collections.swap(provider.mRoutes,
                                         sourceIndex, targetIndex++);
                                 // 2. Update the route's contents.
-                                int changes = route.updateDescriptor(routeDescriptor);
-                                // 3. Notify clients about changes.
-                                if (changes != 0) {
-                                    if ((changes & RouteInfo.CHANGE_GENERAL) != 0) {
-                                        if (DEBUG) {
-                                            Log.d(TAG, "Route changed: " + route);
+                                if (route instanceof RouteGroup) {
+                                    updatedGroups.add(new Pair(route, routeDescriptor));
+                                } else {
+                                    // 3. Notify clients about changes.
+                                    if (updateRouteDescriptorAndNotify(route, routeDescriptor)
+                                            != 0) {
+                                        if (route == mSelectedRoute) {
+                                            selectedRouteDescriptorChanged = true;
                                         }
-                                        mCallbackHandler.post(
-                                                CallbackHandler.MSG_ROUTE_CHANGED, route);
                                     }
-                                    if ((changes & RouteInfo.CHANGE_VOLUME) != 0) {
-                                        if (DEBUG) {
-                                            Log.d(TAG, "Route volume changed: " + route);
-                                        }
-                                        mCallbackHandler.post(
-                                                CallbackHandler.MSG_ROUTE_VOLUME_CHANGED, route);
-                                    }
-                                    if ((changes & RouteInfo.CHANGE_PRESENTATION_DISPLAY) != 0) {
-                                        if (DEBUG) {
-                                            Log.d(TAG, "Route presentation display changed: "
-                                                    + route);
-                                        }
-                                        mCallbackHandler.post(CallbackHandler.
-                                                MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED, route);
-                                    }
-                                    if (route == mSelectedRoute) {
-                                        selectedRouteDescriptorChanged = true;
-                                    }
+                                }
+                            }
+                        }
+                        // Update the new and/or existing groups.
+                        for (Pair<RouteInfo, MediaRouteDescriptor> pair : addedGroups) {
+                            RouteInfo route = pair.first;
+                            route.maybeUpdateDescriptor(pair.second);
+                            if (DEBUG) {
+                                Log.d(TAG, "Route added: " + route);
+                            }
+                            mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route);
+                        }
+                        for (Pair<RouteInfo, MediaRouteDescriptor> pair : updatedGroups) {
+                            RouteInfo route = pair.first;
+                            if (updateRouteDescriptorAndNotify(route, pair.second) != 0) {
+                                if (route == mSelectedRoute) {
+                                    selectedRouteDescriptorChanged = true;
                                 }
                             }
                         }
@@ -1996,7 +2274,7 @@
                 for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) {
                     // 1. Delete the route's contents.
                     RouteInfo route = provider.mRoutes.get(i);
-                    route.updateDescriptor(null);
+                    route.maybeUpdateDescriptor(null);
                     // 2. Remove the route from the list.
                     mRoutes.remove(route);
                 }
@@ -2025,18 +2303,52 @@
             }
         }
 
+        private int updateRouteDescriptorAndNotify(RouteInfo route,
+                MediaRouteDescriptor routeDescriptor) {
+            int changes = route.maybeUpdateDescriptor(routeDescriptor);
+            if (changes != 0) {
+                if ((changes & RouteInfo.CHANGE_GENERAL) != 0) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Route changed: " + route);
+                    }
+                    mCallbackHandler.post(
+                            CallbackHandler.MSG_ROUTE_CHANGED, route);
+                }
+                if ((changes & RouteInfo.CHANGE_VOLUME) != 0) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Route volume changed: " + route);
+                    }
+                    mCallbackHandler.post(
+                            CallbackHandler.MSG_ROUTE_VOLUME_CHANGED, route);
+                }
+                if ((changes & RouteInfo.CHANGE_PRESENTATION_DISPLAY) != 0) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Route presentation display changed: "
+                                + route);
+                    }
+                    mCallbackHandler.post(CallbackHandler.
+                            MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED, route);
+                }
+            }
+            return changes;
+        }
+
         private String assignRouteUniqueId(ProviderInfo provider, String routeDescriptorId) {
             // Although route descriptor ids are unique within a provider, it's
             // possible for there to be two providers with the same package name.
             // Therefore we must dedupe the composite id.
-            String uniqueId = provider.getComponentName().flattenToShortString()
-                    + ":" + routeDescriptorId;
+            String componentName = provider.getComponentName().flattenToShortString();
+            String uniqueId = componentName + ":" + routeDescriptorId;
             if (findRouteByUniqueId(uniqueId) < 0) {
+                mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), uniqueId);
                 return uniqueId;
             }
+            Log.w(TAG, "Either " + routeDescriptorId + " isn't unique in " + componentName
+                    + " or we're trying to assign a unique ID for an already added route");
             for (int i = 2; ; i++) {
                 String newUniqueId = String.format(Locale.US, "%s_%d", uniqueId, i);
                 if (findRouteByUniqueId(newUniqueId) < 0) {
+                    mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), newUniqueId);
                     return newUniqueId;
                 }
             }
@@ -2052,6 +2364,11 @@
             return -1;
         }
 
+        private String getUniqueId(ProviderInfo provider, String routeDescriptorId) {
+            String componentName = provider.getComponentName().flattenToShortString();
+            return mUniqueIdMap.get(new Pair(componentName, routeDescriptorId));
+        }
+
         private void updateSelectedRouteIfNeeded(boolean selectedRouteDescriptorChanged) {
             // Update default route.
             if (mDefaultRoute != null && !isRouteSelectable(mDefaultRoute)) {
@@ -2134,6 +2451,13 @@
                         mSelectedRouteController.onRelease();
                         mSelectedRouteController = null;
                     }
+                    if (mGroupMemberControllers != null) {
+                        for (RouteController controller : mGroupMemberControllers.values()) {
+                            controller.onUnselect();
+                            controller.onRelease();
+                        }
+                        mGroupMemberControllers = null;
+                    }
                 }
 
                 mSelectedRoute = route;
@@ -2148,6 +2472,17 @@
                         Log.d(TAG, "Route selected: " + mSelectedRoute);
                     }
                     mCallbackHandler.post(CallbackHandler.MSG_ROUTE_SELECTED, mSelectedRoute);
+
+                    if (mSelectedRoute instanceof RouteGroup) {
+                        mGroupMemberControllers = new HashMap<>();
+                        RouteGroup group = (RouteGroup) mSelectedRoute;
+                        for (RouteInfo groupMember : group.getRoutes()) {
+                            RouteController controller = groupMember.getProviderInstance()
+                                    .onCreateRouteController(groupMember.mDescriptorId);
+                            controller.onSelect();
+                            mGroupMemberControllers.put(groupMember.mDescriptorId, controller);
+                        }
+                    }
                 }
 
                 updatePlaybackInfoFromSelectedRoute();
diff --git a/v7/palette/api/23.txt b/v7/palette/api/23.0.0.txt
similarity index 100%
rename from v7/palette/api/23.txt
rename to v7/palette/api/23.0.0.txt
diff --git a/v7/palette/api/23.1.0.txt b/v7/palette/api/23.1.0.txt
new file mode 100644
index 0000000..fac6a55
--- /dev/null
+++ b/v7/palette/api/23.1.0.txt
@@ -0,0 +1,56 @@
+package android.support.v7.graphics {
+
+  public final class Palette {
+    method public static android.support.v7.graphics.Palette.Builder from(android.graphics.Bitmap);
+    method public static android.support.v7.graphics.Palette from(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+    method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap);
+    method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap, int);
+    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, int, android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public int getDarkMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDarkMutedSwatch();
+    method public int getDarkVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getDarkVibrantSwatch();
+    method public int getLightMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getLightMutedSwatch();
+    method public int getLightVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getLightVibrantSwatch();
+    method public int getMutedColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getMutedSwatch();
+    method public java.util.List<android.support.v7.graphics.Palette.Swatch> getSwatches();
+    method public int getVibrantColor(int);
+    method public android.support.v7.graphics.Palette.Swatch getVibrantSwatch();
+  }
+
+  public static final class Palette.Builder {
+    ctor public Palette.Builder(android.graphics.Bitmap);
+    ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+    method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+    method public android.support.v7.graphics.Palette.Builder clearFilters();
+    method public android.support.v7.graphics.Palette.Builder clearRegion();
+    method public android.support.v7.graphics.Palette generate();
+    method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
+    method public android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+    method public android.support.v7.graphics.Palette.Builder setRegion(int, int, int, int);
+  }
+
+  public static abstract interface Palette.Filter {
+    method public abstract boolean isAllowed(int, float[]);
+  }
+
+  public static abstract interface Palette.PaletteAsyncListener {
+    method public abstract void onGenerated(android.support.v7.graphics.Palette);
+  }
+
+  public static final class Palette.Swatch {
+    ctor public Palette.Swatch(int, int);
+    method public int getBodyTextColor();
+    method public float[] getHsl();
+    method public int getPopulation();
+    method public int getRgb();
+    method public int getTitleTextColor();
+  }
+
+}
+
diff --git a/v7/palette/api/current.txt b/v7/palette/api/current.txt
index 1b6c745..3b24b77 100644
--- a/v7/palette/api/current.txt
+++ b/v7/palette/api/current.txt
@@ -7,6 +7,7 @@
     method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap, int);
     method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, android.support.v7.graphics.Palette.PaletteAsyncListener);
     method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, int, android.support.v7.graphics.Palette.PaletteAsyncListener);
+    method public int getColorForTarget(android.support.v7.graphics.Target, int);
     method public int getDarkMutedColor(int);
     method public android.support.v7.graphics.Palette.Swatch getDarkMutedSwatch();
     method public int getDarkVibrantColor(int);
@@ -17,7 +18,9 @@
     method public android.support.v7.graphics.Palette.Swatch getLightVibrantSwatch();
     method public int getMutedColor(int);
     method public android.support.v7.graphics.Palette.Swatch getMutedSwatch();
+    method public android.support.v7.graphics.Palette.Swatch getSwatchForTarget(android.support.v7.graphics.Target);
     method public java.util.List<android.support.v7.graphics.Palette.Swatch> getSwatches();
+    method public java.util.List<android.support.v7.graphics.Target> getTargets();
     method public int getVibrantColor(int);
     method public android.support.v7.graphics.Palette.Swatch getVibrantSwatch();
   }
@@ -26,11 +29,16 @@
     ctor public Palette.Builder(android.graphics.Bitmap);
     ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
     method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+    method public android.support.v7.graphics.Palette.Builder addTarget(android.support.v7.graphics.Target);
     method public android.support.v7.graphics.Palette.Builder clearFilters();
+    method public android.support.v7.graphics.Palette.Builder clearRegion();
+    method public android.support.v7.graphics.Palette.Builder clearTargets();
     method public android.support.v7.graphics.Palette generate();
     method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
     method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
-    method public android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+    method public android.support.v7.graphics.Palette.Builder resizeBitmapArea(int);
+    method public deprecated android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+    method public android.support.v7.graphics.Palette.Builder setRegion(int, int, int, int);
   }
 
   public static abstract interface Palette.Filter {
@@ -50,5 +58,40 @@
     method public int getTitleTextColor();
   }
 
+  public final class Target {
+    method public float getLightnessWeight();
+    method public float getMaximumLightness();
+    method public float getMaximumSaturation();
+    method public float getMinimumLightness();
+    method public float getMinimumSaturation();
+    method public float getPopulationWeight();
+    method public float getSaturationWeight();
+    method public float getTargetLightness();
+    method public float getTargetSaturation();
+    method public boolean isExclusive();
+    field public static final android.support.v7.graphics.Target DARK_MUTED;
+    field public static final android.support.v7.graphics.Target DARK_VIBRANT;
+    field public static final android.support.v7.graphics.Target LIGHT_MUTED;
+    field public static final android.support.v7.graphics.Target LIGHT_VIBRANT;
+    field public static final android.support.v7.graphics.Target MUTED;
+    field public static final android.support.v7.graphics.Target VIBRANT;
+  }
+
+  public static final class Target.Builder {
+    ctor public Target.Builder();
+    ctor public Target.Builder(android.support.v7.graphics.Target);
+    method public android.support.v7.graphics.Target build();
+    method public android.support.v7.graphics.Target.Builder setExclusive(boolean);
+    method public android.support.v7.graphics.Target.Builder setLightnessWeight(float);
+    method public android.support.v7.graphics.Target.Builder setMaximumLightness(float);
+    method public android.support.v7.graphics.Target.Builder setMaximumSaturation(float);
+    method public android.support.v7.graphics.Target.Builder setMinimumLightness(float);
+    method public android.support.v7.graphics.Target.Builder setMinimumSaturation(float);
+    method public android.support.v7.graphics.Target.Builder setPopulationWeight(float);
+    method public android.support.v7.graphics.Target.Builder setSaturationWeight(float);
+    method public android.support.v7.graphics.Target.Builder setTargetLightness(float);
+    method public android.support.v7.graphics.Target.Builder setTargetSaturation(float);
+  }
+
 }
 
diff --git a/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java b/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java
index dc0ec1d..3635c3e 100644
--- a/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java
+++ b/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java
@@ -66,4 +66,72 @@
 
         assertEquals(swatches, p.getSwatches());
     }
+
+    public void testRegionWhole() {
+        Palette.Builder b = new Palette.Builder(mSource);
+        b.setRegion(0, 0, mSource.getWidth(), mSource.getHeight());
+
+        Throwable thrown = null;
+        try {
+            b.generate();
+        } catch (Exception e) {
+            thrown = e;
+        }
+        assertNull(thrown);
+    }
+
+    public void testRegionUpperLeft() {
+        Palette.Builder b = new Palette.Builder(mSource);
+        b.setRegion(0, 0, mSource.getWidth() / 2, mSource.getHeight() / 2);
+
+        Throwable thrown = null;
+        try {
+            b.generate();
+        } catch (Exception e) {
+            thrown = e;
+        }
+        assertNull(thrown);
+    }
+
+    public void testRegionBottomRight() {
+        Palette.Builder b = new Palette.Builder(mSource);
+        b.setRegion(mSource.getWidth() / 2, mSource.getHeight() / 2,
+                mSource.getWidth(), mSource.getHeight());
+
+        Throwable thrown = null;
+        try {
+            b.generate();
+        } catch (Exception e) {
+            thrown = e;
+        }
+        assertNull(thrown);
+    }
+
+    public void testOnePixelTallBitmap() {
+        Bitmap bitmap = Bitmap.createBitmap(1000, 1, Bitmap.Config.ARGB_8888);
+
+        Palette.Builder b = new Palette.Builder(bitmap);
+
+        Throwable thrown = null;
+        try {
+            b.generate();
+        } catch (Exception e) {
+            thrown = e;
+        }
+        assertNull(thrown);
+    }
+
+    public void testOnePixelWideBitmap() {
+        Bitmap bitmap = Bitmap.createBitmap(1, 1000, Bitmap.Config.ARGB_8888);
+
+        Palette.Builder b = new Palette.Builder(bitmap);
+
+        Throwable thrown = null;
+        try {
+            b.generate();
+        } catch (Exception e) {
+            thrown = e;
+        }
+        assertNull(thrown);
+    }
 }
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java b/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java
deleted file mode 100644
index 3ee2bfa..0000000
--- a/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package android.support.v7.graphics;
-
-import android.support.v4.graphics.ColorUtils;
-import android.support.v7.graphics.Palette.Swatch;
-
-import java.util.List;
-
-class DefaultGenerator extends Palette.Generator {
-
-    private static final float TARGET_DARK_LUMA = 0.26f;
-    private static final float MAX_DARK_LUMA = 0.45f;
-
-    private static final float MIN_LIGHT_LUMA = 0.55f;
-    private static final float TARGET_LIGHT_LUMA = 0.74f;
-
-    private static final float MIN_NORMAL_LUMA = 0.3f;
-    private static final float TARGET_NORMAL_LUMA = 0.5f;
-    private static final float MAX_NORMAL_LUMA = 0.7f;
-
-    private static final float TARGET_MUTED_SATURATION = 0.3f;
-    private static final float MAX_MUTED_SATURATION = 0.4f;
-
-    private static final float TARGET_VIBRANT_SATURATION = 1f;
-    private static final float MIN_VIBRANT_SATURATION = 0.35f;
-
-    private static final float WEIGHT_SATURATION = 3f;
-    private static final float WEIGHT_LUMA = 6f;
-    private static final float WEIGHT_POPULATION = 1f;
-
-    private List<Swatch> mSwatches;
-
-    private int mHighestPopulation;
-
-    private Swatch mVibrantSwatch;
-    private Swatch mMutedSwatch;
-    private Swatch mDarkVibrantSwatch;
-    private Swatch mDarkMutedSwatch;
-    private Swatch mLightVibrantSwatch;
-    private Swatch mLightMutedSwatch;
-
-    @Override
-    public void generate(final List<Swatch> swatches) {
-        mSwatches = swatches;
-
-        mHighestPopulation = findMaxPopulation();
-
-        generateVariationColors();
-
-        // Now try and generate any missing colors
-        generateEmptySwatches();
-    }
-
-    @Override
-    public Swatch getVibrantSwatch() {
-        return mVibrantSwatch;
-    }
-
-    @Override
-    public Swatch getLightVibrantSwatch() {
-        return mLightVibrantSwatch;
-    }
-
-    @Override
-    public Swatch getDarkVibrantSwatch() {
-        return mDarkVibrantSwatch;
-    }
-
-    @Override
-    public Swatch getMutedSwatch() {
-        return mMutedSwatch;
-    }
-
-    @Override
-    public Swatch getLightMutedSwatch() {
-        return mLightMutedSwatch;
-    }
-
-    @Override
-    public Swatch getDarkMutedSwatch() {
-        return mDarkMutedSwatch;
-    }
-
-    private void generateVariationColors() {
-        mVibrantSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
-                TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
-        mLightVibrantSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
-                TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
-        mDarkVibrantSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
-                TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
-        mMutedSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
-                TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
-
-        mLightMutedSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
-                TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
-
-        mDarkMutedSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
-                TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
-    }
-
-    /**
-     * Try and generate any missing swatches from the swatches we did find.
-     */
-    private void generateEmptySwatches() {
-        if (mVibrantSwatch == null) {
-            // If we do not have a vibrant color...
-            if (mDarkVibrantSwatch != null) {
-                // ...but we do have a dark vibrant, generate the value by modifying the luma
-                final float[] newHsl = copyHslValues(mDarkVibrantSwatch);
-                newHsl[2] = TARGET_NORMAL_LUMA;
-                mVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
-            }
-        }
-
-        if (mDarkVibrantSwatch == null) {
-            // If we do not have a dark vibrant color...
-            if (mVibrantSwatch != null) {
-                // ...but we do have a vibrant, generate the value by modifying the luma
-                final float[] newHsl = copyHslValues(mVibrantSwatch);
-                newHsl[2] = TARGET_DARK_LUMA;
-                mDarkVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
-            }
-        }
-    }
-
-    /**
-     * Find the {@link Palette.Swatch} with the highest population value and return the population.
-     */
-    private int findMaxPopulation() {
-        int population = 0;
-        for (Swatch swatch : mSwatches) {
-            population = Math.max(population, swatch.getPopulation());
-        }
-        return population;
-    }
-
-    private Swatch findColorVariation(float targetLuma, float minLuma, float maxLuma,
-            float targetSaturation, float minSaturation, float maxSaturation) {
-        Swatch max = null;
-        float maxValue = 0f;
-
-        for (Swatch swatch : mSwatches) {
-            final float sat = swatch.getHsl()[1];
-            final float luma = swatch.getHsl()[2];
-
-            if (sat >= minSaturation && sat <= maxSaturation &&
-                    luma >= minLuma && luma <= maxLuma &&
-                    !isAlreadySelected(swatch)) {
-                float value = createComparisonValue(sat, targetSaturation, luma, targetLuma,
-                        swatch.getPopulation(), mHighestPopulation);
-                if (max == null || value > maxValue) {
-                    max = swatch;
-                    maxValue = value;
-                }
-            }
-        }
-
-        return max;
-    }
-
-    /**
-     * @return true if we have already selected {@code swatch}
-     */
-    private boolean isAlreadySelected(Swatch swatch) {
-        return mVibrantSwatch == swatch || mDarkVibrantSwatch == swatch ||
-                mLightVibrantSwatch == swatch || mMutedSwatch == swatch ||
-                mDarkMutedSwatch == swatch || mLightMutedSwatch == swatch;
-    }
-
-    private static float createComparisonValue(float saturation, float targetSaturation,
-            float luma, float targetLuma,
-            int population, int maxPopulation) {
-        return createComparisonValue(saturation, targetSaturation, WEIGHT_SATURATION,
-                luma, targetLuma, WEIGHT_LUMA,
-                population, maxPopulation, WEIGHT_POPULATION);
-    }
-
-    private static float createComparisonValue(
-            float saturation, float targetSaturation, float saturationWeight,
-            float luma, float targetLuma, float lumaWeight,
-            int population, int maxPopulation, float populationWeight) {
-        return weightedMean(
-                invertDiff(saturation, targetSaturation), saturationWeight,
-                invertDiff(luma, targetLuma), lumaWeight,
-                population / (float) maxPopulation, populationWeight
-        );
-    }
-
-    /**
-     * Copy a {@link Swatch}'s HSL values into a new float[].
-     */
-    private static float[] copyHslValues(Swatch color) {
-        final float[] newHsl = new float[3];
-        System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
-        return newHsl;
-    }
-
-    /**
-     * Returns a value in the range 0-1. 1 is returned when {@code value} equals the
-     * {@code targetValue} and then decreases as the absolute difference between {@code value} and
-     * {@code targetValue} increases.
-     *
-     * @param value the item's value
-     * @param targetValue the value which we desire
-     */
-    private static float invertDiff(float value, float targetValue) {
-        return 1f - Math.abs(value - targetValue);
-    }
-
-    private static float weightedMean(float... values) {
-        float sum = 0f;
-        float sumWeight = 0f;
-
-        for (int i = 0; i < values.length; i += 2) {
-            float value = values[i];
-            float weight = values[i + 1];
-
-            sum += (value * weight);
-            sumWeight += weight;
-        }
-
-        return sum / sumWeight;
-    }
-}
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 1ffb7a1..d0dff30 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
@@ -18,17 +18,23 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.os.AsyncTask;
 import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.graphics.ColorUtils;
 import android.support.v4.os.AsyncTaskCompat;
+import android.support.v4.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseBooleanArray;
 import android.util.TimingLogger;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * A helper class to extract prominent colors from an image.
@@ -78,7 +84,7 @@
         void onGenerated(Palette palette);
     }
 
-    private static final int DEFAULT_RESIZE_BITMAP_MAX_DIMENSION = 192;
+    private static final int DEFAULT_RESIZE_BITMAP_AREA = 160 * 160;
     private static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
 
     private static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
@@ -138,151 +144,266 @@
     }
 
     private final List<Swatch> mSwatches;
-    private final Generator mGenerator;
+    private final List<Target> mTargets;
 
-    private Palette(List<Swatch> swatches, Generator generator) {
+    private final Map<Target, Swatch> mSelectedSwatches;
+    private final SparseBooleanArray mUsedColors;
+
+    private final int mMaxPopulation;
+
+    private Palette(List<Swatch> swatches, List<Target> targets) {
         mSwatches = swatches;
-        mGenerator = generator;
+        mTargets = targets;
+
+        mUsedColors = new SparseBooleanArray();
+        mSelectedSwatches = new ArrayMap<>();
+
+        mMaxPopulation = findMaxPopulation();
     }
 
     /**
      * Returns all of the swatches which make up the palette.
      */
+    @NonNull
     public List<Swatch> getSwatches() {
         return Collections.unmodifiableList(mSwatches);
     }
 
     /**
+     * Returns the targets used to generate this palette.
+     */
+    @NonNull
+    public List<Target> getTargets() {
+        return Collections.unmodifiableList(mTargets);
+    }
+
+    /**
      * Returns the most vibrant swatch in the palette. Might be null.
+     *
+     * @see Target#VIBRANT
      */
     @Nullable
     public Swatch getVibrantSwatch() {
-        return mGenerator.getVibrantSwatch();
+        return getSwatchForTarget(Target.VIBRANT);
     }
 
     /**
      * Returns a light and vibrant swatch from the palette. Might be null.
+     *
+     * @see Target#LIGHT_VIBRANT
      */
     @Nullable
     public Swatch getLightVibrantSwatch() {
-        return mGenerator.getLightVibrantSwatch();
+        return getSwatchForTarget(Target.LIGHT_VIBRANT);
     }
 
     /**
      * Returns a dark and vibrant swatch from the palette. Might be null.
+     *
+     * @see Target#DARK_VIBRANT
      */
     @Nullable
     public Swatch getDarkVibrantSwatch() {
-        return mGenerator.getDarkVibrantSwatch();
+        return getSwatchForTarget(Target.DARK_VIBRANT);
     }
 
     /**
      * Returns a muted swatch from the palette. Might be null.
+     *
+     * @see Target#MUTED
      */
     @Nullable
     public Swatch getMutedSwatch() {
-        return mGenerator.getMutedSwatch();
+        return getSwatchForTarget(Target.MUTED);
     }
 
     /**
      * Returns a muted and light swatch from the palette. Might be null.
+     *
+     * @see Target#LIGHT_MUTED
      */
     @Nullable
     public Swatch getLightMutedSwatch() {
-        return mGenerator.getLightMutedSwatch();
+        return getSwatchForTarget(Target.LIGHT_MUTED);
     }
 
     /**
      * Returns a muted and dark swatch from the palette. Might be null.
+     *
+     * @see Target#DARK_MUTED
      */
     @Nullable
     public Swatch getDarkMutedSwatch() {
-        return mGenerator.getDarkMutedSwatch();
+        return getSwatchForTarget(Target.DARK_MUTED);
     }
 
     /**
      * Returns the most vibrant color in the palette as an RGB packed int.
      *
      * @param defaultColor value to return if the swatch isn't available
+     * @see #getVibrantSwatch()
      */
     @ColorInt
-    public int getVibrantColor(@ColorInt int defaultColor) {
-        Swatch swatch = getVibrantSwatch();
-        return swatch != null ? swatch.getRgb() : defaultColor;
+    public int getVibrantColor(@ColorInt final int defaultColor) {
+        return getColorForTarget(Target.VIBRANT, defaultColor);
     }
 
     /**
      * Returns a light and vibrant color from the palette as an RGB packed int.
      *
      * @param defaultColor value to return if the swatch isn't available
+     * @see #getLightVibrantSwatch()
      */
     @ColorInt
-    public int getLightVibrantColor(@ColorInt int defaultColor) {
-        Swatch swatch = getLightVibrantSwatch();
-        return swatch != null ? swatch.getRgb() : defaultColor;
+    public int getLightVibrantColor(@ColorInt final int defaultColor) {
+        return getColorForTarget(Target.LIGHT_VIBRANT, defaultColor);
     }
 
     /**
      * Returns a dark and vibrant color from the palette as an RGB packed int.
      *
      * @param defaultColor value to return if the swatch isn't available
+     * @see #getDarkVibrantSwatch()
      */
     @ColorInt
-    public int getDarkVibrantColor(@ColorInt int defaultColor) {
-        Swatch swatch = getDarkVibrantSwatch();
-        return swatch != null ? swatch.getRgb() : defaultColor;
+    public int getDarkVibrantColor(@ColorInt final int defaultColor) {
+        return getColorForTarget(Target.DARK_VIBRANT, defaultColor);
     }
 
     /**
      * Returns a muted color from the palette as an RGB packed int.
      *
      * @param defaultColor value to return if the swatch isn't available
+     * @see #getMutedSwatch()
      */
     @ColorInt
-    public int getMutedColor(@ColorInt int defaultColor) {
-        Swatch swatch = getMutedSwatch();
-        return swatch != null ? swatch.getRgb() : defaultColor;
+    public int getMutedColor(@ColorInt final int defaultColor) {
+        return getColorForTarget(Target.MUTED, defaultColor);
     }
 
     /**
      * Returns a muted and light color from the palette as an RGB packed int.
      *
      * @param defaultColor value to return if the swatch isn't available
+     * @see #getLightMutedSwatch()
      */
     @ColorInt
-    public int getLightMutedColor(@ColorInt int defaultColor) {
-        Swatch swatch = getLightMutedSwatch();
-        return swatch != null ? swatch.getRgb() : defaultColor;
+    public int getLightMutedColor(@ColorInt final int defaultColor) {
+        return getColorForTarget(Target.LIGHT_MUTED, defaultColor);
     }
 
     /**
      * Returns a muted and dark color from the palette as an RGB packed int.
      *
      * @param defaultColor value to return if the swatch isn't available
+     * @see #getDarkMutedSwatch()
      */
     @ColorInt
-    public int getDarkMutedColor(@ColorInt int defaultColor) {
-        Swatch swatch = getDarkMutedSwatch();
-        return swatch != null ? swatch.getRgb() : defaultColor;
+    public int getDarkMutedColor(@ColorInt final int defaultColor) {
+        return getColorForTarget(Target.DARK_MUTED, defaultColor);
     }
 
     /**
-     * Scale the bitmap down so that it's largest dimension is {@code targetMaxDimension}.
-     * If {@code bitmap} is smaller than this, then it is returned.
+     * Returns the selected swatch for the given target from the palette, or {@code null} if one
+     * could not be found.
      */
-    private static Bitmap scaleBitmapDown(Bitmap bitmap, final int targetMaxDimension) {
-        final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+    @Nullable
+    public Swatch getSwatchForTarget(@NonNull final Target target) {
+        return mSelectedSwatches.get(target);
+    }
 
-        if (maxDimension <= targetMaxDimension) {
-            // If the bitmap is small enough already, just return it
-            return bitmap;
+    /**
+     * Returns the selected color for the given target from the palette as an RGB packed int.
+     *
+     * @param defaultColor value to return if the swatch isn't available
+     */
+    @ColorInt
+    public int getColorForTarget(@NonNull final Target target, @ColorInt final int defaultColor) {
+        Swatch swatch = getSwatchForTarget(target);
+        return swatch != null ? swatch.getRgb() : defaultColor;
+    }
+
+    private 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++) {
+            final Target target = mTargets.get(i);
+            target.normalizeWeights();
+            mSelectedSwatches.put(target, generateScoredTarget(target));
+        }
+        // We now clear out the used colors
+        mUsedColors.clear();
+    }
+
+    private Swatch generateScoredTarget(final Target target) {
+        final Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
+        if (maxScoreSwatch != null && target.isExclusive()) {
+            // If we have a swatch, and the target is exclusive, add the color to the used list
+            mUsedColors.append(maxScoreSwatch.getRgb(), true);
+        }
+        return maxScoreSwatch;
+    }
+
+    private Swatch getMaxScoredSwatchForTarget(final Target target) {
+        float maxScore = 0;
+        Swatch maxScoreSwatch = null;
+        for (int i = 0, count = mSwatches.size(); i < count; i++) {
+            final Swatch swatch = mSwatches.get(i);
+            if (shouldBeScoredForTarget(swatch, target)) {
+                final float score = generateScore(swatch, target);
+                if (maxScoreSwatch == null || score > maxScore) {
+                    maxScoreSwatch = swatch;
+                    maxScore = score;
+                }
+            }
+        }
+        return maxScoreSwatch;
+    }
+
+    private boolean shouldBeScoredForTarget(final Swatch swatch, final Target target) {
+        // Check whether the HSL values are within the correct ranges, and this color hasn't
+        // been used yet.
+        final float hsl[] = swatch.getHsl();
+        return hsl[1] >= target.getMinimumSaturation() && hsl[1] <= target.getMaximumSaturation()
+                && hsl[2] >= target.getMinimumLightness() && hsl[2] <= target.getMaximumLightness()
+                && !mUsedColors.get(swatch.getRgb());
+    }
+
+    private float generateScore(Swatch swatch, Target target) {
+        final float[] hsl = swatch.getHsl();
+
+        float saturationScore = 0;
+        float luminanceScore = 0;
+        float populationScore = 0;
+
+        if (target.getSaturationWeight() > 0) {
+            saturationScore = target.getSaturationWeight()
+                    * (1f - Math.abs(hsl[1] - target.getTargetSaturation()));
+        }
+        if (target.getLightnessWeight() > 0) {
+            luminanceScore = target.getLightnessWeight()
+                    * (1f - Math.abs(hsl[2] - target.getTargetLightness()));
+        }
+        if (target.getPopulationWeight() > 0) {
+            populationScore = target.getPopulationWeight()
+                    * (swatch.getPopulation() / (float) mMaxPopulation);
         }
 
-        final float scaleRatio = targetMaxDimension / (float) maxDimension;
-        return Bitmap.createScaledBitmap(bitmap,
-                Math.round(bitmap.getWidth() * scaleRatio),
-                Math.round(bitmap.getHeight() * scaleRatio),
-                false);
+        return saturationScore + luminanceScore + populationScore;
+    }
+
+    private int findMaxPopulation() {
+        int max = 0;
+        for (int i = 0, count = mSwatches.size(); i < count; i++) {
+            max = Math.max(mSwatches.get(i).getPopulation(), max);
+        }
+        return max;
+    }
+
+    private static float[] copyHslValues(Swatch color) {
+        final float[] newHsl = new float[3];
+        System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
+        return newHsl;
     }
 
     /**
@@ -316,6 +437,11 @@
             mPopulation = population;
         }
 
+        Swatch(float[] hsl, int population) {
+            this(ColorUtils.HSLToColor(hsl), population);
+            mHsl = hsl;
+        }
+
         /**
          * @return this swatch's RGB color value
          */
@@ -333,8 +459,8 @@
         public float[] getHsl() {
             if (mHsl == null) {
                 mHsl = new float[3];
-                ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
             }
+            ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
             return mHsl;
         }
 
@@ -441,23 +567,36 @@
      * Builder class for generating {@link Palette} instances.
      */
     public static final class Builder {
-        private List<Swatch> mSwatches;
-        private Bitmap mBitmap;
-        private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
-        private int mResizeMaxDimension = DEFAULT_RESIZE_BITMAP_MAX_DIMENSION;
-        private final List<Filter> mFilters = new ArrayList<>();
+        private final List<Swatch> mSwatches;
+        private final Bitmap mBitmap;
 
-        private Generator mGenerator;
+        private final List<Target> mTargets = new ArrayList<>();
+
+        private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
+        private int mResizeArea = DEFAULT_RESIZE_BITMAP_AREA;
+        private int mResizeMaxDimension = -1;
+
+        private final List<Filter> mFilters = new ArrayList<>();
+        private Rect mRegion;
 
         /**
          * Construct a new {@link Builder} using a source {@link Bitmap}
          */
         public Builder(Bitmap bitmap) {
-            this();
             if (bitmap == null || bitmap.isRecycled()) {
                 throw new IllegalArgumentException("Bitmap is not valid");
             }
+            mFilters.add(DEFAULT_FILTER);
             mBitmap = bitmap;
+            mSwatches = null;
+
+            // Add the default targets
+            mTargets.add(Target.LIGHT_VIBRANT);
+            mTargets.add(Target.VIBRANT);
+            mTargets.add(Target.DARK_VIBRANT);
+            mTargets.add(Target.LIGHT_MUTED);
+            mTargets.add(Target.MUTED);
+            mTargets.add(Target.DARK_MUTED);
         }
 
         /**
@@ -465,24 +604,12 @@
          * Typically only used for testing.
          */
         public Builder(List<Swatch> swatches) {
-            this();
             if (swatches == null || swatches.isEmpty()) {
                 throw new IllegalArgumentException("List of Swatches is not valid");
             }
-            mSwatches = swatches;
-        }
-
-        private Builder() {
             mFilters.add(DEFAULT_FILTER);
-        }
-
-        /**
-         * Set the {@link Generator} to use when generating the {@link Palette}. If this is called
-         * with {@code null} then the default generator will be used.
-         */
-        Builder generator(Generator generator) {
-            mGenerator = generator;
-            return this;
+            mSwatches = swatches;
+            mBitmap = null;
         }
 
         /**
@@ -493,6 +620,7 @@
          * the range 10-16. For images which are largely made up of people's faces then this
          * value should be increased to ~24.
          */
+        @NonNull
         public Builder maximumColorCount(int colors) {
             mMaxColors = colors;
             return this;
@@ -503,13 +631,38 @@
          * If the bitmap's largest dimension is greater than the value specified, then the bitmap
          * will be resized so that it's largest dimension matches {@code maxDimension}. If the
          * bitmap is smaller or equal, the original is used as-is.
+         *
+         * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
+         * abnormal aspect ratios more gracefully.
+         *
+         * @param maxDimension the number of pixels that the max dimension should be scaled down to,
+         *                     or any value <= 0 to disable resizing.
+         */
+        @NonNull
+        @Deprecated
+        public Builder resizeBitmapSize(final int maxDimension) {
+            mResizeMaxDimension = maxDimension;
+            mResizeArea = -1;
+            return this;
+        }
+
+        /**
+         * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
+         * If the bitmap's area is greater than the value specified, then the bitmap
+         * will be resized so that it's area matches {@code area}. If the
+         * bitmap is smaller or equal, the original is used as-is.
          * <p>
          * This value has a large effect on the processing time. The larger the resized image is,
          * the greater time it will take to generate the palette. The smaller the image is, the
          * more detail is lost in the resulting image and thus less precision for color selection.
+         *
+         * @param area the number of pixels that the intemediary scaled down Bitmap should cover,
+         *             or any value <= 0 to disable resizing.
          */
-        public Builder resizeBitmapSize(int maxDimension) {
-            mResizeMaxDimension = maxDimension;
+        @NonNull
+        public Builder resizeBitmapArea(final int area) {
+            mResizeArea = area;
+            mResizeMaxDimension = -1;
             return this;
         }
 
@@ -517,17 +670,19 @@
          * Clear all added filters. This includes any default filters added automatically by
          * {@link Palette}.
          */
+        @NonNull
         public Builder clearFilters() {
             mFilters.clear();
             return this;
         }
 
         /**
-         * Add a filter to be able to have fine grained controlled over the colors which are
+         * Add a filter to be able to have fine grained control over which colors are
          * allowed in the resulting palette.
          *
          * @param filter filter to add.
          */
+        @NonNull
         public Builder addFilter(Filter filter) {
             if (filter != null) {
                 mFilters.add(filter);
@@ -536,8 +691,67 @@
         }
 
         /**
+         * Set a region of the bitmap to be used exclusively when calculating the palette.
+         * <p>This only works when the original input is a {@link Bitmap}.</p>
+         *
+         * @param left The left side of the rectangle used for the region.
+         * @param top The top of the rectangle used for the region.
+         * @param right The right side of the rectangle used for the region.
+         * @param bottom The bottom of the rectangle used for the region.
+         */
+        @NonNull
+        public Builder setRegion(int left, int top, int right, int bottom) {
+            if (mBitmap != null) {
+                if (mRegion == null) mRegion = new Rect();
+                // Set the Rect to be initially the whole Bitmap
+                mRegion.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+                // Now just get the intersection with the region
+                if (!mRegion.intersect(left, top, right, bottom)) {
+                    throw new IllegalArgumentException("The given region must intersect with "
+                            + "the Bitmap's dimensions.");
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Clear any previously region set via {@link #setRegion(int, int, int, int)}.
+         */
+        @NonNull
+        public Builder clearRegion() {
+            mRegion = null;
+            return this;
+        }
+
+        /**
+         * Add a target profile to be generated in the palette.
+         *
+         * <p>You can retrieve the result via {@link Palette#getSwatchForTarget(Target)}.</p>
+         */
+        @NonNull
+        public Builder addTarget(@NonNull final Target target) {
+            if (!mTargets.contains(target)) {
+                mTargets.add(target);
+            }
+            return this;
+        }
+
+        /**
+         * Clear all added targets. This includes any default targets added automatically by
+         * {@link Palette}.
+         */
+        @NonNull
+        public Builder clearTargets() {
+            if (mTargets != null) {
+                mTargets.clear();
+            }
+            return this;
+        }
+
+        /**
          * Generate and return the {@link Palette} synchronously.
          */
+        @NonNull
         public Palette generate() {
             final TimingLogger logger = LOG_TIMINGS
                     ? new TimingLogger(LOG_TAG, "Generation")
@@ -546,33 +760,37 @@
             List<Swatch> swatches;
 
             if (mBitmap != null) {
-                // We have a Bitmap so we need to quantization to reduce the number of colors
+                // We have a Bitmap so we need to use quantization to reduce the number of colors
 
-                if (mResizeMaxDimension <= 0) {
-                    throw new IllegalArgumentException(
-                            "Minimum dimension size for resizing should should be >= 1");
-                }
-
-                // First we'll scale down the bitmap so it's largest dimension is as specified
-                final Bitmap scaledBitmap = scaleBitmapDown(mBitmap, mResizeMaxDimension);
+                // First we'll scale down the bitmap if needed
+                final Bitmap bitmap = scaleBitmapDown(mBitmap);
 
                 if (logger != null) {
                     logger.addSplit("Processed Bitmap");
                 }
 
-                // Now generate a quantizer from the Bitmap
-                final int width = scaledBitmap.getWidth();
-                final int height = scaledBitmap.getHeight();
-                final int[] pixels = new int[width * height];
-                scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+                final Rect region = mRegion;
+                if (bitmap != mBitmap && region != null) {
+                    // If we have a scaled bitmap and a selected region, we need to scale down the
+                    // region to match the new scale
+                    final float scale = bitmap.getWidth() / (float) mBitmap.getWidth();
+                    region.left = (int) Math.floor(region.left * scale);
+                    region.top = (int) Math.floor(region.top * scale);
+                    region.right = (int) Math.ceil(region.right * scale);
+                    region.bottom = (int) Math.ceil(region.bottom * scale);
+                }
 
-                final ColorCutQuantizer quantizer = new ColorCutQuantizer(pixels, mMaxColors,
+                // Now generate a quantizer from the Bitmap
+                final ColorCutQuantizer quantizer = new ColorCutQuantizer(
+                        getPixelsFromBitmap(bitmap),
+                        mMaxColors,
                         mFilters.isEmpty() ? null : mFilters.toArray(new Filter[mFilters.size()]));
 
                 // If created a new bitmap, recycle it
-                if (scaledBitmap != mBitmap) {
-                    scaledBitmap.recycle();
+                if (bitmap != mBitmap) {
+                    bitmap.recycle();
                 }
+
                 swatches = quantizer.getQuantizedColors();
 
                 if (logger != null) {
@@ -583,20 +801,10 @@
                 swatches = mSwatches;
             }
 
-            // If we haven't been provided with a generator, use the default
-            if (mGenerator == null) {
-                mGenerator = new DefaultGenerator();
-            }
-
-            // Now call let the Generator do it's thing
-            mGenerator.generate(swatches);
-
-            if (logger != null) {
-                logger.addSplit("Generator.generate() completed");
-            }
-
             // Now create a Palette instance
-            Palette p = new Palette(swatches, mGenerator);
+            final Palette p = new Palette(swatches, mTargets);
+            // And make it generate itself
+            p.generate();
 
             if (logger != null) {
                 logger.addSplit("Created Palette");
@@ -611,6 +819,7 @@
          * {@link PaletteAsyncListener#onGenerated} method will be called with the palette when
          * generated.
          */
+        @NonNull
         public AsyncTask<Bitmap, Void, Palette> generate(final PaletteAsyncListener listener) {
             if (listener == null) {
                 throw new IllegalArgumentException("listener can not be null");
@@ -620,7 +829,12 @@
                     new AsyncTask<Bitmap, Void, Palette>() {
                         @Override
                         protected Palette doInBackground(Bitmap... params) {
-                            return generate();
+                            try {
+                                return generate();
+                            } catch (Exception e) {
+                                Log.e(LOG_TAG, "Exception thrown during async generate", e);
+                                return null;
+                            }
                         }
 
                         @Override
@@ -629,59 +843,62 @@
                         }
                     }, mBitmap);
         }
-    }
 
-    static abstract class Generator {
+        private int[] getPixelsFromBitmap(Bitmap bitmap) {
+            final int bitmapWidth = bitmap.getWidth();
+            final int bitmapHeight = bitmap.getHeight();
+            final int[] pixels = new int[bitmapWidth * bitmapHeight];
 
-        /**
-         * This method will be called with the {@link Palette.Swatch} that represent an image.
-         * You should process this list so that you have appropriate values when the other methods in
-         * class are called.
-         * <p>
-         * This method will probably be called on a background thread.
-         */
-        public abstract void generate(List<Palette.Swatch> swatches);
-
-        /**
-         * Return the most vibrant {@link Palette.Swatch}
-         */
-        public Palette.Swatch getVibrantSwatch() {
-            return null;
+            if (mRegion == null) {
+                // If we don't have a region, return all of the pixels
+                bitmap.getPixels(pixels, 0, bitmapWidth, 0, 0, bitmapWidth, bitmapHeight);
+                return pixels;
+            } else {
+                // If we do have a region, lets create a subset array containing only the region's
+                // pixels
+                final int regionWidth = mRegion.width();
+                final int regionHeight = mRegion.height();
+                // First read the pixels within the region
+                bitmap.getPixels(pixels, 0, bitmapWidth, mRegion.left, mRegion.top,
+                        regionWidth, regionHeight);
+                // pixels now contains all of the pixels, but not packed together. We need to
+                // iterate through each row and copy them into a new smaller array
+                final int[] subsetPixels = new int[regionWidth * regionHeight];
+                for (int row = 0; row < regionHeight; row++) {
+                    System.arraycopy(pixels, ((row + mRegion.top) * bitmapWidth) + mRegion.left,
+                            subsetPixels, row * regionWidth, regionWidth);
+                }
+                return subsetPixels;
+            }
         }
 
         /**
-         * Return a light and vibrant {@link Palette.Swatch}
+         * Scale the bitmap down as needed.
          */
-        public Palette.Swatch getLightVibrantSwatch() {
-            return null;
-        }
+        private Bitmap scaleBitmapDown(final Bitmap bitmap) {
+            double scaleRatio = -1;
 
-        /**
-         * Return a dark and vibrant {@link Palette.Swatch}
-         */
-        public Palette.Swatch getDarkVibrantSwatch() {
-            return null;
-        }
+            if (mResizeArea > 0) {
+                final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
+                if (bitmapArea > mResizeArea) {
+                    scaleRatio = mResizeArea / (double) bitmapArea;
+                }
+            } else if (mResizeMaxDimension > 0) {
+                final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+                if (maxDimension > mResizeMaxDimension) {
+                    scaleRatio = mResizeMaxDimension / (double) maxDimension;
+                }
+            }
 
-        /**
-         * Return a muted {@link Palette.Swatch}
-         */
-        public Palette.Swatch getMutedSwatch() {
-            return null;
-        }
+            if (scaleRatio <= 0) {
+                // Scaling has been disabled or not needed so just return the Bitmap
+                return bitmap;
+            }
 
-        /**
-         * Return a muted and light {@link Palette.Swatch}
-         */
-        public Palette.Swatch getLightMutedSwatch() {
-            return null;
-        }
-
-        /**
-         * Return a muted and dark {@link Palette.Swatch}
-         */
-        public Palette.Swatch getDarkMutedSwatch() {
-            return null;
+            return Bitmap.createScaledBitmap(bitmap,
+                    (int) Math.ceil(bitmap.getWidth() * scaleRatio),
+                    (int) Math.ceil(bitmap.getHeight() * scaleRatio),
+                    false);
         }
     }
 
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
new file mode 100644
index 0000000..8ac8205
--- /dev/null
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright 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.
+ */
+
+package android.support.v7.graphics;
+
+import android.support.annotation.FloatRange;
+
+/**
+ * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
+ * can be created via the {@link Builder} class.
+ *
+ * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
+ * Palette.</p>
+ */
+public final class Target {
+
+    private static final float TARGET_DARK_LUMA = 0.26f;
+    private static final float MAX_DARK_LUMA = 0.45f;
+
+    private static final float MIN_LIGHT_LUMA = 0.55f;
+    private static final float TARGET_LIGHT_LUMA = 0.74f;
+
+    private static final float MIN_NORMAL_LUMA = 0.3f;
+    private static final float TARGET_NORMAL_LUMA = 0.5f;
+    private static final float MAX_NORMAL_LUMA = 0.7f;
+
+    private static final float TARGET_MUTED_SATURATION = 0.3f;
+    private static final float MAX_MUTED_SATURATION = 0.4f;
+
+    private static final float TARGET_VIBRANT_SATURATION = 1f;
+    private static final float MIN_VIBRANT_SATURATION = 0.35f;
+
+    private static final float WEIGHT_SATURATION = 0.24f;
+    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;
+
+    private static final int INDEX_WEIGHT_SAT = 0;
+    private static final int INDEX_WEIGHT_LUMA = 1;
+    private static final int INDEX_WEIGHT_POP = 2;
+
+    /**
+     * A target which has the characteristics of a vibrant color which is light in luminance.
+    */
+    public static final Target LIGHT_VIBRANT;
+
+    /**
+     * A target which has the characteristics of a vibrant color which is neither light or dark.
+     */
+    public static final Target VIBRANT;
+
+    /**
+     * A target which has the characteristics of a vibrant color which is dark in luminance.
+     */
+    public static final Target DARK_VIBRANT;
+
+    /**
+     * A target which has the characteristics of a muted color which is light in luminance.
+     */
+    public static final Target LIGHT_MUTED;
+
+    /**
+     * A target which has the characteristics of a muted color which is neither light or dark.
+     */
+    public static final Target MUTED;
+
+    /**
+     * A target which has the characteristics of a muted color which is dark in luminance.
+     */
+    public static final Target DARK_MUTED;
+
+    static {
+        LIGHT_VIBRANT = new Target();
+        setDefaultLightLightnessValues(LIGHT_VIBRANT);
+        setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
+
+        VIBRANT = new Target();
+        setDefaultNormalLightnessValues(VIBRANT);
+        setDefaultVibrantSaturationValues(VIBRANT);
+
+        DARK_VIBRANT = new Target();
+        setDefaultDarkLightnessValues(DARK_VIBRANT);
+        setDefaultVibrantSaturationValues(DARK_VIBRANT);
+
+        LIGHT_MUTED = new Target();
+        setDefaultLightLightnessValues(LIGHT_MUTED);
+        setDefaultMutedSaturationValues(LIGHT_MUTED);
+
+        MUTED = new Target();
+        setDefaultNormalLightnessValues(MUTED);
+        setDefaultMutedSaturationValues(MUTED);
+
+        DARK_MUTED = new Target();
+        setDefaultDarkLightnessValues(DARK_MUTED);
+        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
+
+    private Target() {
+        setTargetDefaultValues(mSaturationTargets);
+        setTargetDefaultValues(mLightnessTargets);
+        setDefaultWeights();
+    }
+
+    private Target(Target from) {
+        System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
+                mSaturationTargets.length);
+        System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
+                mLightnessTargets.length);
+        System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
+    }
+
+    /**
+     * The minimum saturation value for this target.
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getMinimumSaturation() {
+        return mSaturationTargets[INDEX_MIN];
+    }
+
+    /**
+     * The target saturation value for this target.
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getTargetSaturation() {
+        return mSaturationTargets[INDEX_TARGET];
+    }
+
+    /**
+     * The maximum saturation value for this target.
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getMaximumSaturation() {
+        return mSaturationTargets[INDEX_MAX];
+    }
+
+    /**
+     * The minimum lightness value for this target.
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getMinimumLightness() {
+        return mLightnessTargets[INDEX_MIN];
+    }
+
+    /**
+     * The target lightness value for this target.
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getTargetLightness() {
+        return mLightnessTargets[INDEX_TARGET];
+    }
+
+    /**
+     * The maximum lightness value for this target.
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getMaximumLightness() {
+        return mLightnessTargets[INDEX_MAX];
+    }
+
+    /**
+     * The weight of important that a color's saturation value has on selection.
+     */
+    public float getSaturationWeight() {
+        return mWeights[INDEX_WEIGHT_SAT];
+    }
+
+    /**
+     * The weight of important that a color's lightness value has on selection.
+     */
+    public float getLightnessWeight() {
+        return mWeights[INDEX_WEIGHT_LUMA];
+    }
+
+    /**
+     * The weight of important that a color's population value has on selection.
+     */
+    public float getPopulationWeight() {
+        return mWeights[INDEX_WEIGHT_POP];
+    }
+
+    /**
+     * Returns whether any color selected for this target is exclusive for this target only.
+     *
+     * <p>If false, then the color can be selected for other targets.</p>
+     */
+    public boolean isExclusive() {
+        return mIsExclusive;
+    }
+
+    private static void setTargetDefaultValues(final float[] values) {
+        values[INDEX_MIN] = 0f;
+        values[INDEX_TARGET] = 0.5f;
+        values[INDEX_MAX] = 1f;
+    }
+
+    private void setDefaultWeights() {
+        mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
+        mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
+        mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
+    }
+
+    void normalizeWeights() {
+        float sum = 0;
+        for (int i = 0, z = mWeights.length; i < z; i++) {
+            float weight = mWeights[i];
+            if (weight > 0) {
+                sum += weight;
+            }
+        }
+        if (sum != 0) {
+            for (int i = 0, z = mWeights.length; i < z; i++) {
+                if (mWeights[i] > 0) {
+                    mWeights[i] /= sum;
+                }
+            }
+        }
+    }
+
+    private static void setDefaultDarkLightnessValues(Target target) {
+        target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
+        target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
+    }
+
+    private static void setDefaultNormalLightnessValues(Target target) {
+        target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
+        target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
+        target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
+    }
+
+    private static void setDefaultLightLightnessValues(Target target) {
+        target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
+        target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
+    }
+
+    private static void setDefaultVibrantSaturationValues(Target target) {
+        target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
+        target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
+    }
+
+    private static void setDefaultMutedSaturationValues(Target target) {
+        target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
+        target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
+    }
+
+    /**
+     * Builder class for generating custom {@link Target} instances.
+     */
+    public final static class Builder {
+        private final Target mTarget;
+
+        /**
+         * Create a new {@link Target} builder from scratch.
+         */
+        public Builder() {
+            mTarget = new Target();
+        }
+
+        /**
+         * Create a new builder based on an existing {@link Target}.
+         */
+        public Builder(Target target) {
+            mTarget = new Target(target);
+        }
+
+        /**
+         * Set the minimum saturation value for this target.
+         */
+        public Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
+            mTarget.mSaturationTargets[INDEX_MIN] = value;
+            return this;
+        }
+
+        /**
+         * Set the target/ideal saturation value for this target.
+         */
+        public Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
+            mTarget.mSaturationTargets[INDEX_TARGET] = value;
+            return this;
+        }
+
+        /**
+         * Set the maximum saturation value for this target.
+         */
+        public Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
+            mTarget.mSaturationTargets[INDEX_MAX] = value;
+            return this;
+        }
+
+        /**
+         * Set the minimum lightness value for this target.
+         */
+        public Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
+            mTarget.mLightnessTargets[INDEX_MIN] = value;
+            return this;
+        }
+
+        /**
+         * Set the target/ideal lightness value for this target.
+         */
+        public Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
+            mTarget.mLightnessTargets[INDEX_TARGET] = value;
+            return this;
+        }
+
+        /**
+         * Set the maximum lightness value for this target.
+         */
+        public Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
+            mTarget.mLightnessTargets[INDEX_MAX] = value;
+            return this;
+        }
+
+        /**
+         * Set the weight of important that a color's saturation value has on selection. A weight
+         * of <= 0 means that it has no weight and is ignored.
+         */
+        public Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
+            mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
+            return this;
+        }
+
+        /**
+         * Set the weight of important that a color's lightness value has on selection. A weight
+         * of <= 0 means that it has no weight and is ignored.
+         */
+        public Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
+            mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
+            return this;
+        }
+
+        /**
+         * Set the weight of important that a color's population value has on selection. A weight
+         * of <= 0 means that it has no weight and is ignored.
+         */
+        public Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
+            mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
+            return this;
+        }
+
+        /**
+         * Set whether any color selected for this target is exclusive to this target only.
+         * Defaults to true.
+         *
+         * @param exclusive true if any the color is exclusive to this target, or false is the
+         *                  color can be selected for other targets.
+         */
+        public Builder setExclusive(boolean exclusive) {
+            mTarget.mIsExclusive = exclusive;
+            return this;
+        }
+
+        /**
+         * Builds and returns the resulting {@link Target}.
+         */
+        public Target build() {
+            return mTarget;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/v7/preference/NOTICES.md b/v7/preference/NOTICES.md
new file mode 100644
index 0000000..4fe92cc
--- /dev/null
+++ b/v7/preference/NOTICES.md
@@ -0,0 +1,11 @@
+# Change Log
+
+## [23.1.0](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/v14/preference) (2015-09-28)
+
+**Breakage and deprecation notices:**
+
+- EditTextPreferenceDialogFragmentCompat
+  - onAddEditTextToDialogView has been removed. Any code depending on overriding this method should
+    be moved to onBindDialogView.
+  - The EditText view is now expected to be present in the dialog layout file with the id
+    @android:id/edit, and is no longer created in code.
diff --git a/v7/preference/api/23.txt b/v7/preference/api/23.0.0.txt
similarity index 100%
rename from v7/preference/api/23.txt
rename to v7/preference/api/23.0.0.txt
diff --git a/v7/preference/api/23.1.0.txt b/v7/preference/api/23.1.0.txt
new file mode 100644
index 0000000..7d7aeb1
--- /dev/null
+++ b/v7/preference/api/23.1.0.txt
@@ -0,0 +1,318 @@
+package android.support.v7.preference {
+
+  public class CheckBoxPreference extends android.support.v7.preference.TwoStatePreference {
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
+    ctor public CheckBoxPreference(android.content.Context);
+  }
+
+  public abstract class DialogPreference extends android.support.v7.preference.Preference {
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public DialogPreference(android.content.Context, android.util.AttributeSet);
+    ctor public DialogPreference(android.content.Context);
+    method public android.graphics.drawable.Drawable getDialogIcon();
+    method public int getDialogLayoutResource();
+    method public java.lang.CharSequence getDialogMessage();
+    method public java.lang.CharSequence getDialogTitle();
+    method public java.lang.CharSequence getNegativeButtonText();
+    method public java.lang.CharSequence getPositiveButtonText();
+    method public void setDialogIcon(android.graphics.drawable.Drawable);
+    method public void setDialogIcon(int);
+    method public void setDialogLayoutResource(int);
+    method public void setDialogMessage(java.lang.CharSequence);
+    method public void setDialogMessage(int);
+    method public void setDialogTitle(java.lang.CharSequence);
+    method public void setDialogTitle(int);
+    method public void setNegativeButtonText(java.lang.CharSequence);
+    method public void setNegativeButtonText(int);
+    method public void setPositiveButtonText(java.lang.CharSequence);
+    method public void setPositiveButtonText(int);
+  }
+
+  public static abstract interface DialogPreference.TargetFragment {
+    method public abstract android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+  }
+
+  public class EditTextPreference extends android.support.v7.preference.DialogPreference {
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet);
+    ctor public EditTextPreference(android.content.Context);
+    method public java.lang.String getText();
+    method public void setText(java.lang.String);
+  }
+
+  public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public EditTextPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class ListPreference extends android.support.v7.preference.DialogPreference {
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public ListPreference(android.content.Context, android.util.AttributeSet);
+    ctor public ListPreference(android.content.Context);
+    method public int findIndexOfValue(java.lang.String);
+    method public java.lang.CharSequence[] getEntries();
+    method public java.lang.CharSequence getEntry();
+    method public java.lang.CharSequence[] getEntryValues();
+    method public java.lang.String getValue();
+    method public void setEntries(java.lang.CharSequence[]);
+    method public void setEntries(int);
+    method public void setEntryValues(java.lang.CharSequence[]);
+    method public void setEntryValues(int);
+    method public void setValue(java.lang.String);
+    method public void setValueIndex(int);
+  }
+
+  public class ListPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+    ctor public ListPreferenceDialogFragmentCompat();
+    method public static android.support.v7.preference.ListPreferenceDialogFragmentCompat newInstance(java.lang.String);
+    method public void onDialogClosed(boolean);
+  }
+
+  public class Preference {
+    ctor public Preference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public Preference(android.content.Context, android.util.AttributeSet, int);
+    ctor public Preference(android.content.Context, android.util.AttributeSet);
+    ctor public Preference(android.content.Context);
+    method public boolean callChangeListener(java.lang.Object);
+    method public int compareTo(android.support.v7.preference.Preference);
+    method protected android.support.v7.preference.Preference findPreferenceInHierarchy(java.lang.String);
+    method public android.content.Context getContext();
+    method public java.lang.String getDependency();
+    method public android.os.Bundle getExtras();
+    method public java.lang.String getFragment();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.String getKey();
+    method public final int getLayoutResource();
+    method public android.support.v7.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
+    method public android.support.v7.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
+    method public int getOrder();
+    method protected boolean getPersistedBoolean(boolean);
+    method protected float getPersistedFloat(float);
+    method protected int getPersistedInt(int);
+    method protected long getPersistedLong(long);
+    method protected java.lang.String getPersistedString(java.lang.String);
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.content.SharedPreferences getSharedPreferences();
+    method public boolean getShouldDisableView();
+    method public java.lang.CharSequence getSummary();
+    method public java.lang.CharSequence getTitle();
+    method public final int getWidgetLayoutResource();
+    method public boolean hasKey();
+    method public boolean isEnabled();
+    method public boolean isPersistent();
+    method public boolean isSelectable();
+    method public final boolean isVisible();
+    method protected void notifyChanged();
+    method public void notifyDependencyChange(boolean);
+    method protected void notifyHierarchyChanged();
+    method public void onAttached();
+    method protected void onAttachedToHierarchy(android.support.v7.preference.PreferenceManager);
+    method public void onBindViewHolder(android.support.v7.preference.PreferenceViewHolder);
+    method protected void onClick();
+    method public void onDependencyChanged(android.support.v7.preference.Preference, boolean);
+    method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
+    method public void onParentChanged(android.support.v7.preference.Preference, boolean);
+    method protected void onPrepareForRemoval();
+    method protected void onRestoreInstanceState(android.os.Parcelable);
+    method protected android.os.Parcelable onSaveInstanceState();
+    method protected void onSetInitialValue(boolean, java.lang.Object);
+    method public android.os.Bundle peekExtras();
+    method protected boolean persistBoolean(boolean);
+    method protected boolean persistFloat(float);
+    method protected boolean persistInt(int);
+    method protected boolean persistLong(long);
+    method protected boolean persistString(java.lang.String);
+    method public void restoreHierarchyState(android.os.Bundle);
+    method public void saveHierarchyState(android.os.Bundle);
+    method public void setDefaultValue(java.lang.Object);
+    method public void setDependency(java.lang.String);
+    method public void setEnabled(boolean);
+    method public void setFragment(java.lang.String);
+    method public void setIcon(android.graphics.drawable.Drawable);
+    method public void setIcon(int);
+    method public void setIntent(android.content.Intent);
+    method public void setKey(java.lang.String);
+    method public void setLayoutResource(int);
+    method public void setOnPreferenceChangeListener(android.support.v7.preference.Preference.OnPreferenceChangeListener);
+    method public void setOnPreferenceClickListener(android.support.v7.preference.Preference.OnPreferenceClickListener);
+    method public void setOrder(int);
+    method public void setPersistent(boolean);
+    method public void setSelectable(boolean);
+    method public void setShouldDisableView(boolean);
+    method public void setSummary(java.lang.CharSequence);
+    method public void setSummary(int);
+    method public void setTitle(java.lang.CharSequence);
+    method public void setTitle(int);
+    method public final void setVisible(boolean);
+    method public void setWidgetLayoutResource(int);
+    method public boolean shouldDisableDependents();
+    method protected boolean shouldPersist();
+    field public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
+  }
+
+  public static class Preference.BaseSavedState extends android.view.AbsSavedState {
+    ctor public Preference.BaseSavedState(android.os.Parcel);
+    ctor public Preference.BaseSavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v7.preference.Preference.BaseSavedState> CREATOR;
+  }
+
+  public static abstract interface Preference.OnPreferenceChangeListener {
+    method public abstract boolean onPreferenceChange(android.support.v7.preference.Preference, java.lang.Object);
+  }
+
+  public static abstract interface Preference.OnPreferenceClickListener {
+    method public abstract boolean onPreferenceClick(android.support.v7.preference.Preference);
+  }
+
+  public class PreferenceCategory extends android.support.v7.preference.PreferenceGroup {
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
+    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet);
+    ctor public PreferenceCategory(android.content.Context);
+  }
+
+  public abstract class PreferenceDialogFragmentCompat extends android.support.v4.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+    ctor public PreferenceDialogFragmentCompat();
+    method public android.support.v7.preference.DialogPreference getPreference();
+    method protected void onBindDialogView(android.view.View);
+    method public void onClick(android.content.DialogInterface, int);
+    method protected android.view.View onCreateDialogView(android.content.Context);
+    method public abstract void onDialogClosed(boolean);
+    method protected void onPrepareDialogBuilder(android.support.v7.app.AlertDialog.Builder);
+    field protected static final java.lang.String ARG_KEY = "key";
+  }
+
+  public abstract class PreferenceFragmentCompat extends android.support.v4.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+    ctor public PreferenceFragmentCompat();
+    method public void addPreferencesFromResource(int);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public final android.support.v7.widget.RecyclerView getListView();
+    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+    method public void setPreferencesFromResource(int, java.lang.String);
+    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
+    method public abstract boolean onPreferenceDisplayDialog(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+    method public abstract boolean onPreferenceStartFragment(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
+    method public abstract boolean onPreferenceStartScreen(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.PreferenceScreen);
+  }
+
+  public abstract class PreferenceGroup extends android.support.v7.preference.Preference {
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
+    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet);
+    method public void addItemFromInflater(android.support.v7.preference.Preference);
+    method public boolean addPreference(android.support.v7.preference.Preference);
+    method protected void dispatchRestoreInstanceState(android.os.Bundle);
+    method protected void dispatchSaveInstanceState(android.os.Bundle);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public android.support.v7.preference.Preference getPreference(int);
+    method public int getPreferenceCount();
+    method protected boolean isOnSameScreenAsChildren();
+    method public boolean isOrderingAsAdded();
+    method protected boolean onPrepareAddPreference(android.support.v7.preference.Preference);
+    method public void removeAll();
+    method public boolean removePreference(android.support.v7.preference.Preference);
+    method public void setOrderingAsAdded(boolean);
+  }
+
+  public class PreferenceManager {
+    method public android.support.v7.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
+    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+    method public android.content.Context getContext();
+    method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
+    method public android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener();
+    method public android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener getOnNavigateToScreenListener();
+    method public android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener getOnPreferenceTreeClickListener();
+    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+    method public android.content.SharedPreferences getSharedPreferences();
+    method public int getSharedPreferencesMode();
+    method public java.lang.String getSharedPreferencesName();
+    method public static void setDefaultValues(android.content.Context, int, boolean);
+    method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+    method public void setOnDisplayPreferenceDialogListener(android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener);
+    method public void setOnNavigateToScreenListener(android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener);
+    method public void setOnPreferenceTreeClickListener(android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener);
+    method public boolean setPreferences(android.support.v7.preference.PreferenceScreen);
+    method public void setSharedPreferencesMode(int);
+    method public void setSharedPreferencesName(java.lang.String);
+    method public void showDialog(android.support.v7.preference.Preference);
+    field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
+  }
+
+  public static abstract interface PreferenceManager.OnDisplayPreferenceDialogListener {
+    method public abstract void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+  }
+
+  public static abstract interface PreferenceManager.OnNavigateToScreenListener {
+    method public abstract void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+  }
+
+  public static abstract interface PreferenceManager.OnPreferenceTreeClickListener {
+    method public abstract boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+  }
+
+  public final class PreferenceScreen extends android.support.v7.preference.PreferenceGroup {
+  }
+
+  public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
+    method public android.view.View findViewById(int);
+  }
+
+  public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int);
+    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet);
+    ctor public SwitchPreferenceCompat(android.content.Context);
+    method public java.lang.CharSequence getSwitchTextOff();
+    method public java.lang.CharSequence getSwitchTextOn();
+    method public void setSwitchTextOff(java.lang.CharSequence);
+    method public void setSwitchTextOff(int);
+    method public void setSwitchTextOn(java.lang.CharSequence);
+    method public void setSwitchTextOn(int);
+  }
+
+  public abstract class TwoStatePreference extends android.support.v7.preference.Preference {
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
+    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet);
+    ctor public TwoStatePreference(android.content.Context);
+    method public boolean getDisableDependentsState();
+    method public java.lang.CharSequence getSummaryOff();
+    method public java.lang.CharSequence getSummaryOn();
+    method public boolean isChecked();
+    method public void setChecked(boolean);
+    method public void setDisableDependentsState(boolean);
+    method public void setSummaryOff(java.lang.CharSequence);
+    method public void setSummaryOff(int);
+    method public void setSummaryOn(java.lang.CharSequence);
+    method public void setSummaryOn(int);
+    method protected void syncSummaryView(android.support.v7.preference.PreferenceViewHolder);
+    field protected boolean mChecked;
+  }
+
+}
+
diff --git a/v7/preference/api/current.txt b/v7/preference/api/current.txt
index 6ab53c5..9034fd4 100644
--- a/v7/preference/api/current.txt
+++ b/v7/preference/api/current.txt
@@ -47,7 +47,6 @@
   public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
     ctor public EditTextPreferenceDialogFragmentCompat();
     method public static android.support.v7.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
-    method protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
     method public void onDialogClosed(boolean);
   }
 
@@ -204,6 +203,8 @@
     method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
     method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
     method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+    method public void setDivider(android.graphics.drawable.Drawable);
+    method public void setDividerHeight(int);
     method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
     method public void setPreferencesFromResource(int, java.lang.String);
     field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
@@ -281,6 +282,10 @@
 
   public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
     method public android.view.View findViewById(int);
+    method public boolean isDividerAllowedAbove();
+    method public boolean isDividerAllowedBelow();
+    method public void setDividerAllowedAbove(boolean);
+    method public void setDividerAllowedBelow(boolean);
   }
 
   public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index d93a93d..a0681ed 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -55,3 +55,37 @@
         consumerProguardFiles 'proguard-rules.pro'
     }
 }
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri(rootProject.ext.supportRepoOut)) {
+            }
+
+            pom.project {
+                name 'Android Support Preference v7'
+                description "Android Support Preference v7"
+                url 'http://developer.android.com/tools/extras/support-library.html'
+                inceptionYear '2015'
+
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                        distribution 'repo'
+                    }
+                }
+
+                scm {
+                    url "http://source.android.com"
+                    connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+                }
+                developers {
+                    developer {
+                        name 'The Android Open Source Project'
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/v7/preference/proguard-rules.pro b/v7/preference/proguard-rules.pro
index 07c2b2b..bdcc466 100644
--- a/v7/preference/proguard-rules.pro
+++ b/v7/preference/proguard-rules.pro
@@ -13,5 +13,9 @@
 # limitations under the License.
 
 # Preference objects are inflated via reflection
--keep public class * extends android.support.v7.preference.Preference
-
+-keep public class android.support.v7.preference.Preference {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+-keep public class * extends android.support.v7.preference.Preference {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
diff --git a/v7/preference/res/layout/preference_dialog_edittext.xml b/v7/preference/res/layout/preference_dialog_edittext.xml
index 527a7de..9fbf2b7 100644
--- a/v7/preference/res/layout/preference_dialog_edittext.xml
+++ b/v7/preference/res/layout/preference_dialog_edittext.xml
@@ -23,7 +23,6 @@
     android:overScrollMode="ifContentScrolls">
 
   <LinearLayout
-      android:id="@+id/edittext_container"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:padding="5dip"
@@ -36,6 +35,11 @@
         android:layout_height="wrap_content"
         android:textColor="?android:attr/textColorSecondary" />
 
+      <EditText
+          android:id="@android:id/edit"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content" />
+
   </LinearLayout>
 
 </ScrollView>
diff --git a/v7/preference/res/layout/preference_information.xml b/v7/preference/res/layout/preference_information.xml
index e3be3820..5815c46 100644
--- a/v7/preference/res/layout/preference_information.xml
+++ b/v7/preference/res/layout/preference_information.xml
@@ -33,14 +33,14 @@
         android:layout_marginBottom="6sp"
         android:layout_weight="1">
 
-        <TextView android:id="@+android:id/title"
+        <TextView android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:textAppearance="?android:attr/textAppearanceLarge"
             android:textColor="?android:attr/textColorSecondary" />
 
-        <TextView android:id="@+android:id/summary"
+        <TextView android:id="@android:id/summary"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_below="@android:id/title"
@@ -52,7 +52,7 @@
     </RelativeLayout>
 
     <!-- Preference should place its actual preference widget here. -->
-    <LinearLayout android:id="@+android:id/widget_frame"
+    <LinearLayout android:id="@android:id/widget_frame"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:gravity="center_vertical"
diff --git a/v7/preference/res/values-v17/styles.xml b/v7/preference/res/values-v17/styles.xml
index 20168b2..2184354 100644
--- a/v7/preference/res/values-v17/styles.xml
+++ b/v7/preference/res/values-v17/styles.xml
@@ -19,6 +19,7 @@
     <style name="PreferenceFragment">
         <item name="android:paddingStart">0dp</item>
         <item name="android:paddingEnd">0dp</item>
+        <item name="android:divider">?android:attr/listDivider</item>
     </style>
 
     <style name="PreferenceFragmentList">
diff --git a/v7/preference/res/values/attrs.xml b/v7/preference/res/values/attrs.xml
index b93c1e6..5d39b63 100644
--- a/v7/preference/res/values/attrs.xml
+++ b/v7/preference/res/values/attrs.xml
@@ -1,243 +1,248 @@
 <?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
-  -->
+    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
+    -->
 
 <resources>
-  <declare-styleable name="Theme">
+    <declare-styleable name="Theme">
 
-    <!-- =================== -->
-    <!-- Preference styles   -->
-    <!-- =================== -->
-    <eat-comment />
+        <!-- =================== -->
+        <!-- Preference styles   -->
+        <!-- =================== -->
+        <eat-comment />
 
-    <!-- Theme for inflating Preference objects -->
-    <attr name="preferenceTheme" format="reference" />
+        <!-- Theme for inflating Preference objects -->
+        <attr name="preferenceTheme" format="reference" />
 
-    <!-- Default style for PreferenceScreen. -->
-    <attr name="preferenceScreenStyle" format="reference" />
-    <!-- Default style for the PreferenceActivity. -->
-    <attr name="preferenceActivityStyle" format="reference" />
-    <!-- Default style for Headers pane in PreferenceActivity. -->
-    <attr name="preferenceFragmentStyle" format="reference" />
-    <!-- Default style for PreferenceCategory. -->
-    <attr name="preferenceCategoryStyle" format="reference" />
-    <!-- Default style for Preference. -->
-    <attr name="preferenceStyle" format="reference" />
-    <!-- Default style for informational Preference. -->
-    <attr name="preferenceInformationStyle" format="reference" />
-    <!-- Default style for CheckBoxPreference. -->
-    <attr name="checkBoxPreferenceStyle" format="reference" />
-    <!-- Default style for YesNoPreference. -->
-    <attr name="yesNoPreferenceStyle" format="reference" />
-    <!-- Default style for DialogPreference. -->
-    <attr name="dialogPreferenceStyle" format="reference" />
-    <!-- Default style for EditTextPreference. -->
-    <attr name="editTextPreferenceStyle" format="reference" />
-    <!-- Default style for RingtonePreference. -->
-    <attr name="ringtonePreferenceStyle" format="reference" />
-    <!-- The preference layout that has the child/tabbed effect. -->
-    <attr name="preferenceLayoutChild" format="reference" />
-    <!-- Preference panel style -->
-    <attr name="preferencePanelStyle" format="reference" />
-    <!-- Preference headers panel style -->
-    <attr name="preferenceHeaderPanelStyle" format="reference" />
-    <!-- Preference list style -->
-    <attr name="preferenceListStyle" format="reference" />
-    <!-- Preference fragment list style -->
-    <attr name="preferenceFragmentListStyle" format="reference" />
-    <!-- Preference fragment padding side -->
-    <attr name="preferenceFragmentPaddingSide" format="dimension" />
-    <!-- Default style for switch preferences. -->
-    <attr name="switchPreferenceStyle" format="reference" />
-    <!-- Default style for switch compat preferences. -->
-    <attr name="switchPreferenceCompatStyle" format="reference" />
-    <!-- Default style for seekbar preferences. -->
-    <attr name="seekBarPreferenceStyle" format="reference" />
-  </declare-styleable>
+        <!-- Default style for PreferenceScreen. -->
+        <attr name="preferenceScreenStyle" format="reference" />
+        <!-- Default style for the PreferenceActivity. -->
+        <attr name="preferenceActivityStyle" format="reference" />
+        <!-- Default style for Headers pane in PreferenceActivity. -->
+        <attr name="preferenceFragmentStyle" format="reference" />
+        <!-- Default style for Headers pane in PreferenceActivity. -->
+        <attr name="preferenceFragmentCompatStyle" format="reference" />
+        <!-- Default style for PreferenceCategory. -->
+        <attr name="preferenceCategoryStyle" format="reference" />
+        <!-- Default style for Preference. -->
+        <attr name="preferenceStyle" format="reference" />
+        <!-- Default style for informational Preference. -->
+        <attr name="preferenceInformationStyle" format="reference" />
+        <!-- Default style for CheckBoxPreference. -->
+        <attr name="checkBoxPreferenceStyle" format="reference" />
+        <!-- Default style for YesNoPreference. -->
+        <attr name="yesNoPreferenceStyle" format="reference" />
+        <!-- Default style for DialogPreference. -->
+        <attr name="dialogPreferenceStyle" format="reference" />
+        <!-- Default style for EditTextPreference. -->
+        <attr name="editTextPreferenceStyle" format="reference" />
+        <!-- Default style for RingtonePreference. -->
+        <attr name="ringtonePreferenceStyle" format="reference" />
+        <!-- The preference layout that has the child/tabbed effect. -->
+        <attr name="preferenceLayoutChild" format="reference" />
+        <!-- Preference panel style -->
+        <attr name="preferencePanelStyle" format="reference" />
+        <!-- Preference headers panel style -->
+        <attr name="preferenceHeaderPanelStyle" format="reference" />
+        <!-- Preference list style -->
+        <attr name="preferenceListStyle" format="reference" />
+        <!-- Preference fragment list style -->
+        <attr name="preferenceFragmentListStyle" format="reference" />
+        <!-- Preference fragment padding side -->
+        <attr name="preferenceFragmentPaddingSide" format="dimension" />
+        <!-- Default style for switch preferences. -->
+        <attr name="switchPreferenceStyle" format="reference" />
+        <!-- Default style for switch compat preferences. -->
+        <attr name="switchPreferenceCompatStyle" format="reference" />
+        <!-- Default style for seekbar preferences. -->
+        <attr name="seekBarPreferenceStyle" format="reference" />
+    </declare-styleable>
 
-  <!-- Base attributes available to PreferenceFragment. -->
-  <declare-styleable name="PreferenceFragmentCompat">
-    <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
-    <attr name="layout" />
-    <attr name="android:layout" />
-  </declare-styleable>
+    <!-- Base attributes available to PreferenceFragment. -->
+    <declare-styleable name="PreferenceFragmentCompat">
+        <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
+        <attr name="android:layout" />
+        <!-- List separator to draw between preference views -->
+        <attr name="android:divider" />
+        <!-- List separator height -->
+        <attr name="android:dividerHeight" />
+    </declare-styleable>
 
-  <!-- Base attributes available to PreferenceGroup. -->
-  <declare-styleable name="PreferenceGroup">
-    <!-- Whether to order the Preference under this group as they appear in the XML file.
-         If this is false, the ordering will follow the Preference order attribute and
-         default to alphabetic for those without the order attribute. -->
-    <attr name="orderingFromXml" format="boolean" />
-    <attr name="android:orderingFromXml" />
-  </declare-styleable>
+    <!-- Base attributes available to PreferenceGroup. -->
+    <declare-styleable name="PreferenceGroup">
+        <!-- Whether to order the Preference under this group as they appear in the XML file.
+             If this is false, the ordering will follow the Preference order attribute and
+             default to alphabetic for those without the order attribute. -->
+        <attr name="orderingFromXml" format="boolean" />
+        <attr name="android:orderingFromXml" />
+    </declare-styleable>
 
-  <!-- Base attributes available to Preference. -->
-  <declare-styleable name="Preference">
-    <!-- The optional icon for the preference -->
-    <attr name="icon" />
-    <attr name="android:icon" />
-    <!-- The key to store the Preference value. -->
-    <attr name="key" format="string" />
-    <attr name="android:key" />
-    <!-- The title for the Preference in a PreferenceActivity screen. -->
-    <attr name="title" />
-    <attr name="android:title" />
-    <!-- The summary for the Preference in a PreferenceActivity screen. -->
-    <attr name="summary" format="string" />
-    <attr name="android:summary" />
-    <!-- The order for the Preference (lower values are to be ordered first). If this is not
-         specified, the default ordering will be alphabetic. -->
-    <attr name="order" format="integer" />
-    <attr name="android:order" />
-    <!-- When used inside of a modern PreferenceActivity, this declares
-         a new PreferenceFragment to be shown when the user selects this item. -->
-    <attr name="fragment" format="string" />
-    <attr name="android:fragment" />
-    <!-- The layout for the Preference in a PreferenceActivity screen. This should
-         rarely need to be changed, look at widgetLayout instead. -->
-    <attr name="layout" />
-    <attr name="android:layout" />
-    <!-- The layout for the controllable widget portion of a Preference. This is inflated
-         into the layout for a Preference and should be used more frequently than
-         the layout attribute. For example, a checkbox preference would specify
-         a custom layout (consisting of just the CheckBox) here. -->
-    <attr name="widgetLayout" format="reference" />
-    <attr name="android:widgetLayout" />
-    <!-- Whether the Preference is enabled. -->
-    <attr name="enabled" format="boolean" />
-    <attr name="android:enabled" />
-    <!-- Whether the Preference is selectable. -->
-    <attr name="selectable" format="boolean" />
-    <attr name="android:selectable" />
-    <!-- The key of another Preference that this Preference will depend on.  If the other
-         Preference is not set or is off, this Preference will be disabled. -->
-    <attr name="dependency" format="string" />
-    <attr name="android:dependency" />
-    <!-- Whether the Preference stores its value to the shared preferences. -->
-    <attr name="persistent" format="boolean" />
-    <attr name="android:persistent" />
-    <!-- The default value for the preference, which will be set either if persistence
-         is off or persistence is on and the preference is not found in the persistent
-         storage.  -->
-    <attr name="defaultValue" format="string|boolean|integer|reference|float" />
-    <attr name="android:defaultValue" />
-    <!-- Whether the view of this Preference should be disabled when
-         this Preference is disabled. -->
-    <attr name="shouldDisableView" format="boolean" />
-    <attr name="android:shouldDisableView" />
-  </declare-styleable>
+    <!-- Base attributes available to Preference. -->
+    <declare-styleable name="Preference">
+        <!-- The optional icon for the preference -->
+        <attr name="icon" />
+        <attr name="android:icon" />
+        <!-- The key to store the Preference value. -->
+        <attr name="key" format="string" />
+        <attr name="android:key" />
+        <!-- The title for the Preference in a PreferenceActivity screen. -->
+        <attr name="title" />
+        <attr name="android:title" />
+        <!-- The summary for the Preference in a PreferenceActivity screen. -->
+        <attr name="summary" format="string" />
+        <attr name="android:summary" />
+        <!-- The order for the Preference (lower values are to be ordered first). If this is not
+             specified, the default ordering will be alphabetic. -->
+        <attr name="order" format="integer" />
+        <attr name="android:order" />
+        <!-- When used inside of a modern PreferenceActivity, this declares
+             a new PreferenceFragment to be shown when the user selects this item. -->
+        <attr name="fragment" format="string" />
+        <attr name="android:fragment" />
+        <!-- The layout for the Preference in a PreferenceActivity screen. This should
+             rarely need to be changed, look at widgetLayout instead. -->
+        <attr name="layout" />
+        <attr name="android:layout" />
+        <!-- The layout for the controllable widget portion of a Preference. This is inflated
+             into the layout for a Preference and should be used more frequently than
+             the layout attribute. For example, a checkbox preference would specify
+             a custom layout (consisting of just the CheckBox) here. -->
+        <attr name="widgetLayout" format="reference" />
+        <attr name="android:widgetLayout" />
+        <!-- Whether the Preference is enabled. -->
+        <attr name="enabled" format="boolean" />
+        <attr name="android:enabled" />
+        <!-- Whether the Preference is selectable. -->
+        <attr name="selectable" format="boolean" />
+        <attr name="android:selectable" />
+        <!-- The key of another Preference that this Preference will depend on.  If the other
+             Preference is not set or is off, this Preference will be disabled. -->
+        <attr name="dependency" format="string" />
+        <attr name="android:dependency" />
+        <!-- Whether the Preference stores its value to the shared preferences. -->
+        <attr name="persistent" format="boolean" />
+        <attr name="android:persistent" />
+        <!-- The default value for the preference, which will be set either if persistence
+             is off or persistence is on and the preference is not found in the persistent
+             storage.  -->
+        <attr name="defaultValue" format="string|boolean|integer|reference|float" />
+        <attr name="android:defaultValue" />
+        <!-- Whether the view of this Preference should be disabled when
+             this Preference is disabled. -->
+        <attr name="shouldDisableView" format="boolean" />
+        <attr name="android:shouldDisableView" />
+    </declare-styleable>
 
-  <!-- Base attributes available to CheckBoxPreference. -->
-  <declare-styleable name="CheckBoxPreference">
-    <!-- The summary for the Preference in a PreferenceActivity screen when the
-         CheckBoxPreference is checked. If separate on/off summaries are not
-         needed, the summary attribute can be used instead. -->
-    <attr name="summaryOn" format="string" />
-    <attr name="android:summaryOn" />
-    <!-- The summary for the Preference in a PreferenceActivity screen when the
-         CheckBoxPreference is unchecked. If separate on/off summaries are not
-         needed, the summary attribute can be used instead. -->
-    <attr name="summaryOff" format="string" />
-    <attr name="android:summaryOff" />
-    <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
-         dependents will be disabled when this is unchecked, so the value of this preference is false. -->
-    <attr name="disableDependentsState" format="boolean" />
-    <attr name="android:disableDependentsState" />
-  </declare-styleable>
+    <!-- Base attributes available to CheckBoxPreference. -->
+    <declare-styleable name="CheckBoxPreference">
+        <!-- The summary for the Preference in a PreferenceActivity screen when the
+             CheckBoxPreference is checked. If separate on/off summaries are not
+             needed, the summary attribute can be used instead. -->
+        <attr name="summaryOn" format="string" />
+        <attr name="android:summaryOn" />
+        <!-- The summary for the Preference in a PreferenceActivity screen when the
+             CheckBoxPreference is unchecked. If separate on/off summaries are not
+             needed, the summary attribute can be used instead. -->
+        <attr name="summaryOff" format="string" />
+        <attr name="android:summaryOff" />
+        <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+             dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+        <attr name="disableDependentsState" format="boolean" />
+        <attr name="android:disableDependentsState" />
+    </declare-styleable>
 
-  <!-- Base attributes available to DialogPreference. -->
-  <declare-styleable name="DialogPreference">
-    <!-- The title in the dialog. -->
-    <attr name="dialogTitle" format="string" />
-    <attr name="android:dialogTitle" />
-    <!-- The message in the dialog. If a dialogLayout is provided and contains
-         a TextView with ID android:id/message, this message will be placed in there. -->
-    <attr name="dialogMessage" format="string" />
-    <attr name="android:dialogMessage" />
-    <!-- The icon for the dialog. -->
-    <attr name="dialogIcon" format="reference" />
-    <attr name="android:dialogIcon" />
-    <!-- The positive button text for the dialog. Set to @null to hide the positive button. -->
-    <attr name="positiveButtonText" format="string" />
-    <attr name="android:positiveButtonText" />
-    <!-- The negative button text for the dialog. Set to @null to hide the negative button. -->
-    <attr name="negativeButtonText" format="string" />
-    <attr name="android:negativeButtonText" />
-    <!-- A layout to be used as the content View for the dialog. By default, this shouldn't
-         be needed. If a custom DialogPreference is required, this should be set. For example,
-         the EditTextPreference uses a layout with an EditText as this attribute. -->
-    <attr name="dialogLayout" format="reference" />
-    <attr name="android:dialogLayout" />
-  </declare-styleable>
+    <!-- Base attributes available to DialogPreference. -->
+    <declare-styleable name="DialogPreference">
+        <!-- The title in the dialog. -->
+        <attr name="dialogTitle" format="string" />
+        <attr name="android:dialogTitle" />
+        <!-- The message in the dialog. If a dialogLayout is provided and contains
+             a TextView with ID android:id/message, this message will be placed in there. -->
+        <attr name="dialogMessage" format="string" />
+        <attr name="android:dialogMessage" />
+        <!-- The icon for the dialog. -->
+        <attr name="dialogIcon" format="reference" />
+        <attr name="android:dialogIcon" />
+        <!-- The positive button text for the dialog. Set to @null to hide the positive button. -->
+        <attr name="positiveButtonText" format="string" />
+        <attr name="android:positiveButtonText" />
+        <!-- The negative button text for the dialog. Set to @null to hide the negative button. -->
+        <attr name="negativeButtonText" format="string" />
+        <attr name="android:negativeButtonText" />
+        <!-- A layout to be used as the content View for the dialog. By default, this shouldn't
+             be needed. If a custom DialogPreference is required, this should be set. For example,
+             the EditTextPreference uses a layout with an EditText as this attribute. -->
+        <attr name="dialogLayout" format="reference" />
+        <attr name="android:dialogLayout" />
+    </declare-styleable>
 
-  <!-- Base attributes available to ListPreference. -->
-  <declare-styleable name="ListPreference">
-    <!-- The human-readable array to present as a list. Each entry must have a corresponding
-         index in entryValues. -->
-    <attr name="entries" format="reference" />
-    <attr name="android:entries" />
-    <!-- The array to find the value to save for a preference when an entry from
-         entries is selected. If a user clicks on the second item in entries, the
-         second item in this array will be saved to the preference. -->
-    <attr name="entryValues" format="reference" />
-    <attr name="android:entryValues" />
-  </declare-styleable>
+    <!-- Base attributes available to ListPreference. -->
+    <declare-styleable name="ListPreference">
+        <!-- The human-readable array to present as a list. Each entry must have a corresponding
+             index in entryValues. -->
+        <attr name="entries" format="reference" />
+        <attr name="android:entries" />
+        <!-- The array to find the value to save for a preference when an entry from
+             entries is selected. If a user clicks on the second item in entries, the
+             second item in this array will be saved to the preference. -->
+        <attr name="entryValues" format="reference" />
+        <attr name="android:entryValues" />
+    </declare-styleable>
 
-  <declare-styleable name="MultiSelectListPreference">
-    <!-- The human-readable array to present as a list. Each entry must have a corresponding
-         index in entryValues. -->
-    <attr name="entries" />
-    <attr name="android:entries" />
-    <!-- The array to find the value to save for a preference when an entry from
-         entries is selected. If a user clicks the second item in entries, the
-         second item in this array will be saved to the preference. -->
-    <attr name="entryValues" />
-    <attr name="android:entryValues" />
-  </declare-styleable>
+    <declare-styleable name="MultiSelectListPreference">
+        <!-- The human-readable array to present as a list. Each entry must have a corresponding
+             index in entryValues. -->
+        <attr name="entries" />
+        <attr name="android:entries" />
+        <!-- The array to find the value to save for a preference when an entry from
+             entries is selected. If a user clicks the second item in entries, the
+             second item in this array will be saved to the preference. -->
+        <attr name="entryValues" />
+        <attr name="android:entryValues" />
+    </declare-styleable>
 
-  <declare-styleable name="SwitchPreferenceCompat">
-    <!-- The summary for the Preference in a PreferenceActivity screen when the
-         SwitchPreference is checked. If separate on/off summaries are not
-         needed, the summary attribute can be used instead. -->
-    <attr name="summaryOn" />
-    <attr name="android:summaryOn" />
-    <!-- The summary for the Preference in a PreferenceActivity screen when the
-         SwitchPreference is unchecked. If separate on/off summaries are not
-         needed, the summary attribute can be used instead. -->
-    <attr name="summaryOff" />
-    <attr name="android:summaryOff" />
-    <!-- The text used on the switch itself when in the "on" state.
-         This should be a very SHORT string, as it appears in a small space. -->
-    <attr name="switchTextOn" format="string" />
-    <attr name="android:switchTextOn" />
-    <!-- The text used on the switch itself when in the "off" state.
-         This should be a very SHORT string, as it appears in a small space. -->
-    <attr name="switchTextOff" format="string" />
-    <attr name="android:switchTextOff" />
-    <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
-         dependents will be disabled when this is unchecked, so the value of this preference is false. -->
-    <attr name="disableDependentsState" />
-    <attr name="android:disableDependentsState" />
-  </declare-styleable>
+    <declare-styleable name="SwitchPreferenceCompat">
+        <!-- The summary for the Preference in a PreferenceActivity screen when the
+             SwitchPreference is checked. If separate on/off summaries are not
+             needed, the summary attribute can be used instead. -->
+        <attr name="summaryOn" />
+        <attr name="android:summaryOn" />
+        <!-- The summary for the Preference in a PreferenceActivity screen when the
+             SwitchPreference is unchecked. If separate on/off summaries are not
+             needed, the summary attribute can be used instead. -->
+        <attr name="summaryOff" />
+        <attr name="android:summaryOff" />
+        <!-- The text used on the switch itself when in the "on" state.
+             This should be a very SHORT string, as it appears in a small space. -->
+        <attr name="switchTextOn" format="string" />
+        <attr name="android:switchTextOn" />
+        <!-- The text used on the switch itself when in the "off" state.
+             This should be a very SHORT string, as it appears in a small space. -->
+        <attr name="switchTextOff" format="string" />
+        <attr name="android:switchTextOff" />
+        <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+             dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+        <attr name="disableDependentsState" />
+        <attr name="android:disableDependentsState" />
+    </declare-styleable>
 
-  <declare-styleable name="PreferenceImageView">
-    <attr name="maxWidth" format="dimension" />
-    <attr name="android:maxWidth" />
-    <attr name="maxHeight" format="dimension" />
-    <attr name="android:maxHeight" />
-  </declare-styleable>
+    <declare-styleable name="PreferenceImageView">
+        <attr name="maxWidth" format="dimension" />
+        <attr name="android:maxWidth" />
+        <attr name="maxHeight" format="dimension" />
+        <attr name="android:maxHeight" />
+    </declare-styleable>
 
 </resources>
diff --git a/v7/preference/res/values/styles.xml b/v7/preference/res/values/styles.xml
index 3af31a42..774c0c9 100644
--- a/v7/preference/res/values/styles.xml
+++ b/v7/preference/res/values/styles.xml
@@ -17,47 +17,48 @@
 
 <resources>
     <style name="Preference">
-        <item name="layout">@layout/preference</item>
+        <item name="android:layout">@layout/preference</item>
     </style>
 
     <style name="PreferenceFragment">
         <item name="android:paddingLeft">0dp</item>
         <item name="android:paddingRight">0dp</item>
+        <item name="android:divider">?android:attr/listDivider</item>
     </style>
 
     <style name="Preference.Information">
-        <item name="layout">@layout/preference_information</item>
-        <item name="enabled">false</item>
-        <item name="shouldDisableView">false</item>
+        <item name="android:layout">@layout/preference_information</item>
+        <item name="android:enabled">false</item>
+        <item name="android:shouldDisableView">false</item>
     </style>
 
     <style name="Preference.Category">
-        <item name="layout">@layout/preference_category</item>
+        <item name="android:layout">@layout/preference_category</item>
         <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
-        <item name="shouldDisableView">false</item>
-        <item name="selectable">false</item>
+        <item name="android:shouldDisableView">false</item>
+        <item name="android:selectable">false</item>
     </style>
 
     <style name="Preference.CheckBoxPreference">
-        <item name="widgetLayout">@layout/preference_widget_checkbox</item>
+        <item name="android:widgetLayout">@layout/preference_widget_checkbox</item>
     </style>
 
     <style name="Preference.SwitchPreferenceCompat">
-        <item name="widgetLayout">@layout/preference_widget_switch_compat</item>
-        <item name="switchTextOn">@string/v7_preference_on</item>
-        <item name="switchTextOff">@string/v7_preference_off</item>
+        <item name="android:widgetLayout">@layout/preference_widget_switch_compat</item>
+        <item name="android:switchTextOn">@string/v7_preference_on</item>
+        <item name="android:switchTextOff">@string/v7_preference_off</item>
     </style>
 
     <style name="Preference.PreferenceScreen">
     </style>
 
     <style name="Preference.DialogPreference">
-        <item name="positiveButtonText">@android:string/ok</item>
-        <item name="negativeButtonText">@android:string/cancel</item>
+        <item name="android:positiveButtonText">@android:string/ok</item>
+        <item name="android:negativeButtonText">@android:string/cancel</item>
     </style>
 
     <style name="Preference.DialogPreference.EditTextPreference">
-        <item name="dialogLayout">@layout/preference_dialog_edittext</item>
+        <item name="android:dialogLayout">@layout/preference_dialog_edittext</item>
     </style>
 
     <style name="PreferenceFragmentList">
diff --git a/v7/preference/res/values/themes.xml b/v7/preference/res/values/themes.xml
index c2c2c3c..8a7eaa3 100644
--- a/v7/preference/res/values/themes.xml
+++ b/v7/preference/res/values/themes.xml
@@ -18,7 +18,7 @@
 <resources>
     <style name="PreferenceThemeOverlay">
         <item name="preferenceScreenStyle">@style/Preference.PreferenceScreen</item>
-        <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
+        <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment</item>
         <item name="preferenceCategoryStyle">@style/Preference.Category</item>
         <item name="preferenceStyle">@style/Preference</item>
         <item name="preferenceInformationStyle">@style/Preference.Information</item>
diff --git a/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
index 182cf28..6e7663c 100644
--- a/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
@@ -18,8 +18,6 @@
 
 import android.os.Bundle;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.widget.EditText;
 
 public class EditTextPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
@@ -39,19 +37,14 @@
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
 
-        mEditText = new EditText(view.getContext());
-        // Give it an ID so it can be saved/restored
-        mEditText.setId(android.R.id.edit);
+        mEditText = (EditText) view.findViewById(android.R.id.edit);
+
+        if (mEditText == null) {
+            throw new IllegalStateException("Dialog view must contain an EditText with id" +
+                    " @android:id/edit");
+        }
 
         mEditText.setText(getEditTextPreference().getText());
-
-        ViewParent oldParent = mEditText.getParent();
-        if (oldParent != view) {
-            if (oldParent != null) {
-                ((ViewGroup) oldParent).removeView(mEditText);
-            }
-            onAddEditTextToDialogView(view, mEditText);
-        }
     }
 
     private EditTextPreference getEditTextPreference() {
@@ -65,20 +58,6 @@
         return true;
     }
 
-    /**
-     * Adds the EditText widget of this preference to the dialog's view.
-     *
-     * @param dialogView The dialog view.
-     */
-    protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
-        ViewGroup container = (ViewGroup) dialogView
-                .findViewById(R.id.edittext_container);
-        if (container != null) {
-            container.addView(editText, ViewGroup.LayoutParams.FILL_PARENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-        }
-    }
-
     @Override
     public void onDialogClosed(boolean positiveResult) {
 
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
index 4f210ae..f386592 100644
--- a/v7/preference/src/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -516,6 +516,12 @@
         } else {
             setEnabledStateOnViews(holder.itemView, true);
         }
+
+        final boolean selectable = isSelectable();
+        holder.itemView.setFocusable(selectable);
+
+        holder.setDividerAllowedAbove(selectable);
+        holder.setDividerAllowedBelow(selectable);
     }
 
     /**
@@ -749,9 +755,11 @@
      * @param visible Set false if this preference should be hidden from the list.
      */
     public final void setVisible(boolean visible) {
-        mVisible = visible;
-        if (mListener != null) {
-            mListener.onPreferenceVisibilityChange(this);
+        if (mVisible != visible) {
+            mVisible = visible;
+            if (mListener != null) {
+                mListener.onPreferenceVisibilityChange(this);
+            }
         }
     }
 
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
index 8231d89..221d3ea 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
@@ -18,6 +18,9 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -25,6 +28,7 @@
 import android.support.annotation.XmlRes;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.util.TypedValue;
@@ -51,7 +55,7 @@
  * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
  * denote a screen break--that is the preferences contained within subsequent
  * {@link PreferenceScreen} should be shown on another screen. The preference
- * framework handles showing these other screens from the preference hierarchy.
+ * framework handles this by calling {@link #onNavigateToScreen(PreferenceScreen)}.
  * <p>
  * The preference hierarchy can be formed in multiple ways:
  * <li> From an XML file specifying the hierarchy
@@ -123,10 +127,7 @@
 
     private int mLayoutResId = R.layout.preference_list_fragment;
 
-    /**
-     * The starting request code given out to preference framework.
-     */
-    private static final int FIRST_REQUEST_CODE = 100;
+    private final DividerDecoration mDividerDecoration = new DividerDecoration();
 
     private static final int MSG_BIND_PREFERENCES = 1;
     private Handler mHandler = new Handler() {
@@ -233,15 +234,28 @@
 
         TypedArray a = mStyledContext.obtainStyledAttributes(null,
                 R.styleable.PreferenceFragmentCompat,
-                R.attr.preferenceFragmentStyle,
+                R.attr.preferenceFragmentCompatStyle,
                 0);
 
-        mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
+        mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_android_layout,
                 mLayoutResId);
 
+        final Drawable divider = a.getDrawable(
+                R.styleable.PreferenceFragmentCompat_android_divider);
+        final int dividerHeight = a.getInt(
+                R.styleable.PreferenceFragmentCompat_android_dividerHeight, -1);
+
         a.recycle();
 
-        final View view = inflater.inflate(mLayoutResId, container, false);
+        // Need to theme the inflater to pick up the preferenceFragmentListStyle
+        final TypedValue tv = new TypedValue();
+        getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
+        final int theme = tv.resourceId;
+
+        final Context themedContext = new ContextThemeWrapper(inflater.getContext(), theme);
+        final LayoutInflater themedInflater = inflater.cloneInContext(themedContext);
+
+        final View view = themedInflater.inflate(mLayoutResId, container, false);
 
         final View rawListContainer = view.findViewById(R.id.list_container);
         if (!(rawListContainer instanceof ViewGroup)) {
@@ -251,18 +265,49 @@
 
         final ViewGroup listContainer = (ViewGroup) rawListContainer;
 
-        final RecyclerView listView = onCreateRecyclerView(inflater, listContainer,
+        final RecyclerView listView = onCreateRecyclerView(themedInflater, listContainer,
                 savedInstanceState);
         if (listView == null) {
             throw new RuntimeException("Could not create RecyclerView");
         }
 
         mList = listView;
+
+        listView.addItemDecoration(mDividerDecoration);
+        setDivider(divider);
+        if (dividerHeight != -1) {
+            setDividerHeight(dividerHeight);
+        }
+
         listContainer.addView(mList);
         mHandler.post(mRequestFocus);
         return view;
     }
 
+    /**
+     * Sets the drawable that will be drawn between each item in the list.
+     * <p>
+     * <strong>Note:</strong> If the drawable does not have an intrinsic
+     * height, you should also call {@link #setDividerHeight(int)}.
+     *
+     * @param divider the drawable to use
+     * @attr ref R.styleable#PreferenceFragmentCompat_android_divider
+     */
+    public void setDivider(Drawable divider) {
+        mDividerDecoration.setDivider(divider);
+    }
+
+    /**
+     * Sets the height of the divider that will be drawn between each item in the list. Calling
+     * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
+     *
+     * @param height The new height of the divider in pixels.
+     * @attr ref R.styleable#PreferenceFragmentCompat_android_dividerHeight
+     */
+    public void setDividerHeight(int height) {
+        mDividerDecoration.setDividerHeight(height);
+    }
+
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
@@ -574,4 +619,78 @@
     public Fragment getCallbackFragment() {
         return null;
     }
+
+    private class DividerDecoration extends RecyclerView.ItemDecoration {
+
+        private Drawable mDivider;
+        private int mDividerHeight;
+
+        @Override
+        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+            if (mDivider == null) {
+                return;
+            }
+            final int childCount = parent.getChildCount();
+            final int width = parent.getWidth();
+            for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+                final View view = parent.getChildAt(childViewIndex);
+                if (shouldDrawDividerAbove(view, parent)) {
+                    int top = (int) ViewCompat.getY(view);
+                    mDivider.setBounds(0, top, width, top + mDividerHeight);
+                    mDivider.draw(c);
+                }
+                if (shouldDrawDividerBelow(view, parent)) {
+                    int top = (int) ViewCompat.getY(view) + view.getHeight();
+                    mDivider.setBounds(0, top, width, top + mDividerHeight);
+                    mDivider.draw(c);
+                }
+            }
+        }
+
+        @Override
+        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                RecyclerView.State state) {
+            if (shouldDrawDividerAbove(view, parent)) {
+                outRect.top = mDividerHeight;
+            }
+            if (shouldDrawDividerBelow(view, parent)) {
+                outRect.bottom = mDividerHeight;
+            }
+        }
+
+        private boolean shouldDrawDividerAbove(View view, RecyclerView parent) {
+            final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
+            return holder.getAdapterPosition() == 0 &&
+                    ((PreferenceViewHolder) holder).isDividerAllowedAbove();
+        }
+
+        private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
+            final PreferenceViewHolder holder =
+                    (PreferenceViewHolder) parent.getChildViewHolder(view);
+            boolean nextAllowed = true;
+            int index = parent.indexOfChild(view);
+            if (index < parent.getChildCount() - 1) {
+                final View nextView = parent.getChildAt(index + 1);
+                final PreferenceViewHolder nextHolder =
+                        (PreferenceViewHolder) parent.getChildViewHolder(nextView);
+                nextAllowed = nextHolder.isDividerAllowedAbove();
+            }
+            return nextAllowed && holder.isDividerAllowedBelow();
+        }
+
+        public void setDivider(Drawable divider) {
+            if (divider != null) {
+                mDividerHeight = divider.getIntrinsicHeight();
+            } else {
+                mDividerHeight = 0;
+            }
+            mDivider = divider;
+            mList.invalidateItemDecorations();
+        }
+
+        public void setDividerHeight(int dividerHeight) {
+            mDividerHeight = dividerHeight;
+            mList.invalidateItemDecorations();
+        }
+    }
 }
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
index 9943087..c4ccc66 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
@@ -79,6 +79,14 @@
         private int widgetResId;
         private String name;
 
+        public PreferenceLayout() {}
+
+        public PreferenceLayout(PreferenceLayout other) {
+            resId = other.resId;
+            widgetResId = other.widgetResId;
+            name = other.name;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (!(o instanceof PreferenceLayout)) {
@@ -249,7 +257,14 @@
 
         mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout);
 
-        return mPreferenceLayouts.indexOf(mTempPreferenceLayout);
+        int viewType = mPreferenceLayouts.indexOf(mTempPreferenceLayout);
+        if (viewType != -1) {
+            return viewType;
+        } else {
+            viewType = mPreferenceLayouts.size();
+            mPreferenceLayouts.add(new PreferenceLayout(mTempPreferenceLayout));
+            return viewType;
+        }
     }
 
     @Override
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
index c7e247c..f9eaf22 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
@@ -28,6 +28,8 @@
  */
 public class PreferenceViewHolder extends RecyclerView.ViewHolder {
     private final SparseArray<View> mCachedViews = new SparseArray<>(4);
+    private boolean mDividerAllowedAbove;
+    private boolean mDividerAllowedBelow;
 
     /* package */ PreferenceViewHolder(View itemView) {
         super(itemView);
@@ -58,4 +60,44 @@
             return v;
         }
     }
+
+    /**
+     * Dividers are only drawn between items if both items allow it, or above the first and below
+     * the last item if that item allows it.
+     *
+     * @return true if dividers are allowed above this item
+     */
+    public boolean isDividerAllowedAbove() {
+        return mDividerAllowedAbove;
+    }
+
+    /**
+     * Dividers are only drawn between items if both items allow it, or above the first and below
+     * the last item if that item allows it.
+     *
+     * @param allowed false to prevent dividers being drawn above this item
+     */
+    public void setDividerAllowedAbove(boolean allowed) {
+        mDividerAllowedAbove = allowed;
+    }
+
+    /**
+     * Dividers are only drawn between items if both items allow it, or above the first and below
+     * the last item if that item allows it.
+     *
+     * @return true if dividers are allowed below this item
+     */
+    public boolean isDividerAllowedBelow() {
+        return mDividerAllowedBelow;
+    }
+
+    /**
+     * Dividers are only drawn between items if both items allow it, or above the first and below
+     * the last item if that item allows it.
+     *
+     * @param allowed false to prevent dividers being drawn below this item
+     */
+    public void setDividerAllowedBelow(boolean allowed) {
+        mDividerAllowedBelow = allowed;
+    }
 }
diff --git a/v7/recyclerview/api/23.txt b/v7/recyclerview/api/23.0.0.txt
similarity index 100%
rename from v7/recyclerview/api/23.txt
rename to v7/recyclerview/api/23.0.0.txt
diff --git a/v7/recyclerview/api/23.1.0.txt b/v7/recyclerview/api/23.1.0.txt
new file mode 100644
index 0000000..1f91036
--- /dev/null
+++ b/v7/recyclerview/api/23.1.0.txt
@@ -0,0 +1,864 @@
+package android.support.v7.recyclerview {
+
+  public final class R {
+    ctor public R();
+  }
+
+  public static final class R.attr {
+    ctor public R.attr();
+    field public static int layoutManager;
+    field public static int reverseLayout;
+    field public static int spanCount;
+    field public static int stackFromEnd;
+  }
+
+  public static final class R.dimen {
+    ctor public R.dimen();
+    field public static int item_touch_helper_max_drag_scroll_per_frame;
+  }
+
+  public static final class R.id {
+    ctor public R.id();
+    field public static int item_touch_helper_previous_elevation;
+  }
+
+  public static final class R.styleable {
+    ctor public R.styleable();
+    field public static final int[] RecyclerView;
+    field public static int RecyclerView_android_orientation;
+    field public static int RecyclerView_layoutManager;
+    field public static int RecyclerView_reverseLayout;
+    field public static int RecyclerView_spanCount;
+    field public static int RecyclerView_stackFromEnd;
+  }
+
+}
+
+package android.support.v7.util {
+
+  public class AsyncListUtil {
+    ctor public AsyncListUtil(java.lang.Class<T>, int, android.support.v7.util.AsyncListUtil.DataCallback<T>, android.support.v7.util.AsyncListUtil.ViewCallback);
+    method public T getItem(int);
+    method public int getItemCount();
+    method public void onRangeChanged();
+    method public void refresh();
+  }
+
+  public static abstract class AsyncListUtil.DataCallback {
+    ctor public AsyncListUtil.DataCallback();
+    method public abstract void fillData(T[], int, int);
+    method public int getMaxCachedTiles();
+    method public void recycleData(T[], int);
+    method public abstract int refreshData();
+  }
+
+  public static abstract class AsyncListUtil.ViewCallback {
+    ctor public AsyncListUtil.ViewCallback();
+    method public void extendRangeInto(int[], int[], int);
+    method public abstract void getItemRangeInto(int[]);
+    method public abstract void onDataRefresh();
+    method public abstract void onItemLoaded(int);
+    field public static final int HINT_SCROLL_ASC = 2; // 0x2
+    field public static final int HINT_SCROLL_DESC = 1; // 0x1
+    field public static final int HINT_SCROLL_NONE = 0; // 0x0
+  }
+
+  public class SortedList {
+    ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>);
+    ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>, int);
+    method public int add(T);
+    method public void addAll(T[], boolean);
+    method public void addAll(T...);
+    method public void addAll(java.util.Collection<T>);
+    method public void beginBatchedUpdates();
+    method public void clear();
+    method public void endBatchedUpdates();
+    method public T get(int) throws java.lang.IndexOutOfBoundsException;
+    method public int indexOf(T);
+    method public void recalculatePositionOfItemAt(int);
+    method public boolean remove(T);
+    method public T removeItemAt(int);
+    method public int size();
+    method public void updateItemAt(int, T);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class SortedList.BatchedCallback extends android.support.v7.util.SortedList.Callback {
+    ctor public SortedList.BatchedCallback(android.support.v7.util.SortedList.Callback<T2>);
+    method public boolean areContentsTheSame(T2, T2);
+    method public boolean areItemsTheSame(T2, T2);
+    method public int compare(T2, T2);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public static abstract class SortedList.Callback implements java.util.Comparator {
+    ctor public SortedList.Callback();
+    method public abstract boolean areContentsTheSame(T2, T2);
+    method public abstract boolean areItemsTheSame(T2, T2);
+    method public abstract int compare(T2, T2);
+    method public abstract void onChanged(int, int);
+    method public abstract void onInserted(int, int);
+    method public abstract void onMoved(int, int);
+    method public abstract void onRemoved(int, int);
+  }
+
+}
+
+package android.support.v7.widget {
+
+  public class DefaultItemAnimator extends android.support.v7.widget.SimpleItemAnimator {
+    ctor public DefaultItemAnimator();
+    method public boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void endAnimations();
+    method public boolean isRunning();
+    method public void runPendingAnimations();
+  }
+
+  public class GridLayoutManager extends android.support.v7.widget.LinearLayoutManager {
+    ctor public GridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public GridLayoutManager(android.content.Context, int);
+    ctor public GridLayoutManager(android.content.Context, int, int, boolean);
+    method public int getSpanCount();
+    method public android.support.v7.widget.GridLayoutManager.SpanSizeLookup getSpanSizeLookup();
+    method public void setSpanCount(int);
+    method public void setSpanSizeLookup(android.support.v7.widget.GridLayoutManager.SpanSizeLookup);
+    field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
+  }
+
+  public static final class GridLayoutManager.DefaultSpanSizeLookup extends android.support.v7.widget.GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.DefaultSpanSizeLookup();
+    method public int getSpanSize(int);
+  }
+
+  public static class GridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+    ctor public GridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public GridLayoutManager.LayoutParams(int, int);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public GridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public int getSpanIndex();
+    method public int getSpanSize();
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public static abstract class GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.SpanSizeLookup();
+    method public int getSpanGroupIndex(int, int);
+    method public int getSpanIndex(int, int);
+    method public abstract int getSpanSize(int);
+    method public void invalidateSpanIndexCache();
+    method public boolean isSpanIndexCacheEnabled();
+    method public void setSpanIndexCacheEnabled(boolean);
+  }
+
+  public class LinearLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager implements android.support.v7.widget.helper.ItemTouchHelper.ViewDropHandler {
+    ctor public LinearLayoutManager(android.content.Context);
+    ctor public LinearLayoutManager(android.content.Context, int, boolean);
+    ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
+    method public int findFirstCompletelyVisibleItemPosition();
+    method public int findFirstVisibleItemPosition();
+    method public int findLastCompletelyVisibleItemPosition();
+    method public int findLastVisibleItemPosition();
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method protected int getExtraLayoutSpace(android.support.v7.widget.RecyclerView.State);
+    method public int getOrientation();
+    method public boolean getRecycleChildrenOnDetach();
+    method public boolean getReverseLayout();
+    method public boolean getStackFromEnd();
+    method protected boolean isLayoutRTL();
+    method public boolean isSmoothScrollbarEnabled();
+    method public void prepareForDrop(android.view.View, android.view.View, int, int);
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setOrientation(int);
+    method public void setRecycleChildrenOnDetach(boolean);
+    method public void setReverseLayout(boolean);
+    method public void setSmoothScrollbarEnabled(boolean);
+    method public void setStackFromEnd(boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  protected static class LinearLayoutManager.LayoutChunkResult {
+    ctor protected LinearLayoutManager.LayoutChunkResult();
+    field public int mConsumed;
+    field public boolean mFinished;
+    field public boolean mFocusable;
+    field public boolean mIgnoreConsumed;
+  }
+
+  public abstract class LinearSmoothScroller extends android.support.v7.widget.RecyclerView.SmoothScroller {
+    ctor public LinearSmoothScroller(android.content.Context);
+    method public int calculateDtToFit(int, int, int, int, int);
+    method public int calculateDxToMakeVisible(android.view.View, int);
+    method public int calculateDyToMakeVisible(android.view.View, int);
+    method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
+    method protected int calculateTimeForDeceleration(int);
+    method protected int calculateTimeForScrolling(int);
+    method public abstract android.graphics.PointF computeScrollVectorForPosition(int);
+    method protected int getHorizontalSnapPreference();
+    method protected int getVerticalSnapPreference();
+    method protected void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected void onStart();
+    method protected void onStop();
+    method protected void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected void updateActionForInterimTarget(android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    field public static final int SNAP_TO_ANY = 0; // 0x0
+    field public static final int SNAP_TO_END = 1; // 0x1
+    field public static final int SNAP_TO_START = -1; // 0xffffffff
+    field protected final android.view.animation.DecelerateInterpolator mDecelerateInterpolator;
+    field protected int mInterimTargetDx;
+    field protected int mInterimTargetDy;
+    field protected final android.view.animation.LinearInterpolator mLinearInterpolator;
+    field protected android.graphics.PointF mTargetVector;
+  }
+
+  public abstract class OrientationHelper {
+    method public static android.support.v7.widget.OrientationHelper createHorizontalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public static android.support.v7.widget.OrientationHelper createOrientationHelper(android.support.v7.widget.RecyclerView.LayoutManager, int);
+    method public static android.support.v7.widget.OrientationHelper createVerticalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public abstract int getDecoratedEnd(android.view.View);
+    method public abstract int getDecoratedMeasurement(android.view.View);
+    method public abstract int getDecoratedMeasurementInOther(android.view.View);
+    method public abstract int getDecoratedStart(android.view.View);
+    method public abstract int getEnd();
+    method public abstract int getEndAfterPadding();
+    method public abstract int getEndPadding();
+    method public abstract int getStartAfterPadding();
+    method public abstract int getTotalSpace();
+    method public int getTotalSpaceChange();
+    method public abstract void offsetChild(android.view.View, int);
+    method public abstract void offsetChildren(int);
+    method public void onLayoutComplete();
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field protected final android.support.v7.widget.RecyclerView.LayoutManager mLayoutManager;
+  }
+
+  public class RecyclerView extends android.view.ViewGroup {
+    ctor public RecyclerView(android.content.Context);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet, int);
+    method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration, int);
+    method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+    method public void addOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void addOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+    method public void addOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void clearOnChildAttachStateChangeListeners();
+    method public void clearOnScrollListeners();
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+    method public boolean drawChild(android.graphics.Canvas, android.view.View, long);
+    method public android.view.View findChildViewUnder(float, float);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForAdapterPosition(int);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForItemId(long);
+    method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForLayoutPosition(int);
+    method public deprecated android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForPosition(int);
+    method public boolean fling(int, int);
+    method public android.support.v7.widget.RecyclerView.Adapter getAdapter();
+    method public int getChildAdapterPosition(android.view.View);
+    method public long getChildItemId(android.view.View);
+    method public int getChildLayoutPosition(android.view.View);
+    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 android.support.v7.widget.RecyclerView.ItemAnimator getItemAnimator();
+    method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+    method public int getMaxFlingVelocity();
+    method public int getMinFlingVelocity();
+    method public android.support.v7.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
+    method public int getScrollState();
+    method public boolean hasFixedSize();
+    method public boolean hasPendingAdapterUpdates();
+    method public void invalidateItemDecorations();
+    method public boolean isAnimating();
+    method public boolean isComputingLayout();
+    method public boolean isLayoutFrozen();
+    method public void offsetChildrenHorizontal(int);
+    method public void offsetChildrenVertical(int);
+    method public void onChildAttachedToWindow(android.view.View);
+    method public void onChildDetachedFromWindow(android.view.View);
+    method public void onDraw(android.graphics.Canvas);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void onScrollStateChanged(int);
+    method public void onScrolled(int, int);
+    method public void removeItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+    method public void removeOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void removeOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+    method public void removeOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void scrollToPosition(int);
+    method public void setAccessibilityDelegateCompat(android.support.v7.widget.RecyclerViewAccessibilityDelegate);
+    method public void setAdapter(android.support.v7.widget.RecyclerView.Adapter);
+    method public void setChildDrawingOrderCallback(android.support.v7.widget.RecyclerView.ChildDrawingOrderCallback);
+    method public void setHasFixedSize(boolean);
+    method public void setItemAnimator(android.support.v7.widget.RecyclerView.ItemAnimator);
+    method public void setItemViewCacheSize(int);
+    method public void setLayoutFrozen(boolean);
+    method public void setLayoutManager(android.support.v7.widget.RecyclerView.LayoutManager);
+    method public deprecated void setOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+    method public void setRecycledViewPool(android.support.v7.widget.RecyclerView.RecycledViewPool);
+    method public void setRecyclerListener(android.support.v7.widget.RecyclerView.RecyclerListener);
+    method public void setScrollingTouchSlop(int);
+    method public void setViewCacheExtension(android.support.v7.widget.RecyclerView.ViewCacheExtension);
+    method public void smoothScrollBy(int, int);
+    method public void smoothScrollToPosition(int);
+    method public void stopScroll();
+    method public void swapAdapter(android.support.v7.widget.RecyclerView.Adapter, boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_TYPE = -1; // 0xffffffff
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+    field public static final int NO_POSITION = -1; // 0xffffffff
+    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
+    field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
+    field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static abstract class RecyclerView.Adapter {
+    ctor public RecyclerView.Adapter();
+    method public final void bindViewHolder(VH, int);
+    method public final VH createViewHolder(android.view.ViewGroup, int);
+    method public abstract int getItemCount();
+    method public long getItemId(int);
+    method public int getItemViewType(int);
+    method public final boolean hasObservers();
+    method public final boolean hasStableIds();
+    method public final void notifyDataSetChanged();
+    method public final void notifyItemChanged(int);
+    method public final void notifyItemChanged(int, java.lang.Object);
+    method public final void notifyItemInserted(int);
+    method public final void notifyItemMoved(int, int);
+    method public final void notifyItemRangeChanged(int, int);
+    method public final void notifyItemRangeChanged(int, int, java.lang.Object);
+    method public final void notifyItemRangeInserted(int, int);
+    method public final void notifyItemRangeRemoved(int, int);
+    method public final void notifyItemRemoved(int);
+    method public void onAttachedToRecyclerView(android.support.v7.widget.RecyclerView);
+    method public abstract void onBindViewHolder(VH, int);
+    method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object>);
+    method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDetachedFromRecyclerView(android.support.v7.widget.RecyclerView);
+    method public boolean onFailedToRecycleView(VH);
+    method public void onViewAttachedToWindow(VH);
+    method public void onViewDetachedFromWindow(VH);
+    method public void onViewRecycled(VH);
+    method public void registerAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+    method public void setHasStableIds(boolean);
+    method public void unregisterAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+  }
+
+  public static abstract class RecyclerView.AdapterDataObserver {
+    ctor public RecyclerView.AdapterDataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeChanged(int, int, java.lang.Object);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeMoved(int, int, int);
+    method public void onItemRangeRemoved(int, int);
+  }
+
+  public static abstract interface RecyclerView.ChildDrawingOrderCallback {
+    method public abstract int onGetChildDrawingOrder(int, int);
+  }
+
+  public static abstract class RecyclerView.ItemAnimator {
+    ctor public RecyclerView.ItemAnimator();
+    method public abstract boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationsFinished();
+    method public abstract void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public abstract void endAnimations();
+    method public long getAddDuration();
+    method public long getChangeDuration();
+    method public long getMoveDuration();
+    method public long getRemoveDuration();
+    method public abstract boolean isRunning();
+    method public final boolean isRunning(android.support.v7.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+    method public void onAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder, int, java.util.List<java.lang.Object>);
+    method public abstract void runPendingAnimations();
+    method public void setAddDuration(long);
+    method public void setChangeDuration(long);
+    method public void setMoveDuration(long);
+    method public void setRemoveDuration(long);
+    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+    field public static final int FLAG_CHANGED = 2; // 0x2
+    field public static final int FLAG_INVALIDATED = 4; // 0x4
+    field public static final int FLAG_MOVED = 2048; // 0x800
+    field public static final int FLAG_REMOVED = 8; // 0x8
+  }
+
+  public static abstract class RecyclerView.ItemAnimator.AdapterChanges implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
+    method public abstract void onAnimationsFinished();
+  }
+
+  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    field public int bottom;
+    field public int changeFlags;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public static abstract class RecyclerView.ItemDecoration {
+    ctor public RecyclerView.ItemDecoration();
+    method public deprecated void getItemOffsets(android.graphics.Rect, int, android.support.v7.widget.RecyclerView);
+    method public void getItemOffsets(android.graphics.Rect, android.view.View, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public deprecated void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+    method public void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+    method public deprecated void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+  }
+
+  public static abstract class RecyclerView.LayoutManager {
+    ctor public RecyclerView.LayoutManager();
+    method public void addDisappearingView(android.view.View);
+    method public void addDisappearingView(android.view.View, int);
+    method public void addView(android.view.View);
+    method public void addView(android.view.View, int);
+    method public void assertInLayoutOrScroll(java.lang.String);
+    method public void assertNotInLayoutOrScroll(java.lang.String);
+    method public void attachView(android.view.View, int, android.support.v7.widget.RecyclerView.LayoutParams);
+    method public void attachView(android.view.View, int);
+    method public void attachView(android.view.View);
+    method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
+    method public boolean canScrollHorizontally();
+    method public boolean canScrollVertically();
+    method public boolean checkLayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public int computeHorizontalScrollExtent(android.support.v7.widget.RecyclerView.State);
+    method public int computeHorizontalScrollOffset(android.support.v7.widget.RecyclerView.State);
+    method public int computeHorizontalScrollRange(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollExtent(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollOffset(android.support.v7.widget.RecyclerView.State);
+    method public int computeVerticalScrollRange(android.support.v7.widget.RecyclerView.State);
+    method public void detachAndScrapAttachedViews(android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachAndScrapView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachAndScrapViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+    method public void detachView(android.view.View);
+    method public void detachViewAt(int);
+    method public void endAnimation(android.view.View);
+    method public android.view.View findViewByPosition(int);
+    method public abstract android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.content.Context, android.util.AttributeSet);
+    method public int getBaseline();
+    method public int getBottomDecorationHeight(android.view.View);
+    method public android.view.View getChildAt(int);
+    method public int getChildCount();
+    method public static int getChildMeasureSpec(int, int, int, boolean);
+    method public boolean getClipToPadding();
+    method public int getColumnCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getDecoratedBottom(android.view.View);
+    method public int getDecoratedLeft(android.view.View);
+    method public int getDecoratedMeasuredHeight(android.view.View);
+    method public int getDecoratedMeasuredWidth(android.view.View);
+    method public int getDecoratedRight(android.view.View);
+    method public int getDecoratedTop(android.view.View);
+    method public android.view.View getFocusedChild();
+    method public int getHeight();
+    method public int getItemCount();
+    method public int getItemViewType(android.view.View);
+    method public int getLayoutDirection();
+    method public int getLeftDecorationWidth(android.view.View);
+    method public int getMinimumHeight();
+    method public int getMinimumWidth();
+    method public int getPaddingBottom();
+    method public int getPaddingEnd();
+    method public int getPaddingLeft();
+    method public int getPaddingRight();
+    method public int getPaddingStart();
+    method public int getPaddingTop();
+    method public int getPosition(android.view.View);
+    method public static android.support.v7.widget.RecyclerView.LayoutManager.Properties getProperties(android.content.Context, android.util.AttributeSet, int, int);
+    method public int getRightDecorationWidth(android.view.View);
+    method public int getRowCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getSelectionModeForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public int getTopDecorationHeight(android.view.View);
+    method public int getWidth();
+    method public boolean hasFocus();
+    method public void ignoreView(android.view.View);
+    method public boolean isAttachedToWindow();
+    method public boolean isFocused();
+    method public boolean isLayoutHierarchical(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public boolean isSmoothScrolling();
+    method public void layoutDecorated(android.view.View, int, int, int, int);
+    method public void measureChild(android.view.View, int, int);
+    method public void measureChildWithMargins(android.view.View, int, int);
+    method public void moveView(int, int);
+    method public void offsetChildrenHorizontal(int);
+    method public void offsetChildrenVertical(int);
+    method public void onAdapterChanged(android.support.v7.widget.RecyclerView.Adapter, android.support.v7.widget.RecyclerView.Adapter);
+    method public boolean onAddFocusables(android.support.v7.widget.RecyclerView, java.util.ArrayList<android.view.View>, int, int);
+    method public void onAttachedToWindow(android.support.v7.widget.RecyclerView);
+    method public deprecated void onDetachedFromWindow(android.support.v7.widget.RecyclerView);
+    method public void onDetachedFromWindow(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.Recycler);
+    method public android.view.View onFocusSearchFailed(android.view.View, int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onInitializeAccessibilityNodeInfoForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method public android.view.View onInterceptFocusSearch(android.view.View, int);
+    method public void onItemsAdded(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsChanged(android.support.v7.widget.RecyclerView);
+    method public void onItemsMoved(android.support.v7.widget.RecyclerView, int, int, int);
+    method public void onItemsRemoved(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int, java.lang.Object);
+    method public void onLayoutChildren(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    method public void onMeasure(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, int);
+    method public deprecated boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.view.View, android.view.View);
+    method public boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, android.view.View, android.view.View);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void onScrollStateChanged(int);
+    method public boolean performAccessibilityAction(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, android.os.Bundle);
+    method public boolean performAccessibilityActionForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, int, android.os.Bundle);
+    method public void postOnAnimation(java.lang.Runnable);
+    method public void removeAllViews();
+    method public void removeAndRecycleAllViews(android.support.v7.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+    method public boolean removeCallbacks(java.lang.Runnable);
+    method public void removeDetachedView(android.view.View);
+    method public void removeView(android.view.View);
+    method public void removeViewAt(int);
+    method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
+    method public void requestLayout();
+    method public void requestSimpleAnimationsInNextLayout();
+    method public int scrollHorizontallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+    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 setMeasuredDimension(int, int);
+    method public void smoothScrollToPosition(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, int);
+    method public void startSmoothScroll(android.support.v7.widget.RecyclerView.SmoothScroller);
+    method public void stopIgnoringView(android.view.View);
+    method public boolean supportsPredictiveItemAnimations();
+  }
+
+  public static class RecyclerView.LayoutManager.Properties {
+    ctor public RecyclerView.LayoutManager.Properties();
+    field public int orientation;
+    field public boolean reverseLayout;
+    field public int spanCount;
+    field public boolean stackFromEnd;
+  }
+
+  public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public RecyclerView.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public RecyclerView.LayoutParams(int, int);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public RecyclerView.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public int getViewAdapterPosition();
+    method public int getViewLayoutPosition();
+    method public deprecated int getViewPosition();
+    method public boolean isItemChanged();
+    method public boolean isItemRemoved();
+    method public boolean isViewInvalid();
+    method public boolean viewNeedsUpdate();
+  }
+
+  public static abstract interface RecyclerView.OnChildAttachStateChangeListener {
+    method public abstract void onChildViewAttachedToWindow(android.view.View);
+    method public abstract void onChildViewDetachedFromWindow(android.view.View);
+  }
+
+  public static abstract interface RecyclerView.OnItemTouchListener {
+    method public abstract boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+    method public abstract void onRequestDisallowInterceptTouchEvent(boolean);
+    method public abstract void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public static abstract class RecyclerView.OnScrollListener {
+    ctor public RecyclerView.OnScrollListener();
+    method public void onScrollStateChanged(android.support.v7.widget.RecyclerView, int);
+    method public void onScrolled(android.support.v7.widget.RecyclerView, int, int);
+  }
+
+  public static class RecyclerView.RecycledViewPool {
+    ctor public RecyclerView.RecycledViewPool();
+    method public void clear();
+    method public android.support.v7.widget.RecyclerView.ViewHolder getRecycledView(int);
+    method public void putRecycledView(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setMaxRecycledViews(int, int);
+  }
+
+  public final class RecyclerView.Recycler {
+    ctor public RecyclerView.Recycler();
+    method public void bindViewToPosition(android.view.View, int);
+    method public void clear();
+    method public int convertPreLayoutPositionToPostLayout(int);
+    method public java.util.List<android.support.v7.widget.RecyclerView.ViewHolder> getScrapList();
+    method public android.view.View getViewForPosition(int);
+    method public void recycleView(android.view.View);
+    method public void setViewCacheSize(int);
+  }
+
+  public static abstract interface RecyclerView.RecyclerListener {
+    method public abstract void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+  }
+
+  public static class RecyclerView.SimpleOnItemTouchListener implements android.support.v7.widget.RecyclerView.OnItemTouchListener {
+    ctor public RecyclerView.SimpleOnItemTouchListener();
+    method public boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public static abstract class RecyclerView.SmoothScroller {
+    ctor public RecyclerView.SmoothScroller();
+    method public android.view.View findViewByPosition(int);
+    method public int getChildCount();
+    method public int getChildPosition(android.view.View);
+    method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+    method public int getTargetPosition();
+    method public deprecated void instantScrollToPosition(int);
+    method public boolean isPendingInitialRun();
+    method public boolean isRunning();
+    method protected void normalize(android.graphics.PointF);
+    method protected void onChildAttachedToWindow(android.view.View);
+    method protected abstract void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method protected abstract void onStart();
+    method protected abstract void onStop();
+    method protected abstract void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+    method public void setTargetPosition(int);
+    method protected final void stop();
+  }
+
+  public static class RecyclerView.SmoothScroller.Action {
+    ctor public RecyclerView.SmoothScroller.Action(int, int);
+    ctor public RecyclerView.SmoothScroller.Action(int, int, int);
+    ctor public RecyclerView.SmoothScroller.Action(int, int, int, android.view.animation.Interpolator);
+    method public int getDuration();
+    method public int getDx();
+    method public int getDy();
+    method public android.view.animation.Interpolator getInterpolator();
+    method public void jumpTo(int);
+    method public void setDuration(int);
+    method public void setDx(int);
+    method public void setDy(int);
+    method public void setInterpolator(android.view.animation.Interpolator);
+    method public void update(int, int, int, android.view.animation.Interpolator);
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+  }
+
+  public static class RecyclerView.State {
+    ctor public RecyclerView.State();
+    method public boolean didStructureChange();
+    method public T get(int);
+    method public int getItemCount();
+    method public int getTargetScrollPosition();
+    method public boolean hasTargetScrollPosition();
+    method public boolean isPreLayout();
+    method public void put(int, java.lang.Object);
+    method public void remove(int);
+    method public boolean willRunPredictiveAnimations();
+    method public boolean willRunSimpleAnimations();
+  }
+
+  public static abstract class RecyclerView.ViewCacheExtension {
+    ctor public RecyclerView.ViewCacheExtension();
+    method public abstract android.view.View getViewForPositionAndType(android.support.v7.widget.RecyclerView.Recycler, int, int);
+  }
+
+  public static abstract class RecyclerView.ViewHolder {
+    ctor public RecyclerView.ViewHolder(android.view.View);
+    method public final int getAdapterPosition();
+    method public final long getItemId();
+    method public final int getItemViewType();
+    method public final int getLayoutPosition();
+    method public final int getOldPosition();
+    method public final deprecated int getPosition();
+    method public final boolean isRecyclable();
+    method public final void setIsRecyclable(boolean);
+    field public final android.view.View itemView;
+  }
+
+  public class RecyclerViewAccessibilityDelegate extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate(android.support.v7.widget.RecyclerView);
+  }
+
+  public abstract class SimpleItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+    ctor public SimpleItemAnimator();
+    method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean getSupportsChangeAnimations();
+    method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setSupportsChangeAnimations(boolean);
+  }
+
+  public class StaggeredGridLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager {
+    ctor public StaggeredGridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public StaggeredGridLayoutManager(int, int);
+    method public int[] findFirstCompletelyVisibleItemPositions(int[]);
+    method public int[] findFirstVisibleItemPositions(int[]);
+    method public int[] findLastCompletelyVisibleItemPositions(int[]);
+    method public int[] findLastVisibleItemPositions(int[]);
+    method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public int getGapStrategy();
+    method public int getOrientation();
+    method public boolean getReverseLayout();
+    method public int getSpanCount();
+    method public void invalidateSpanAssignments();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setGapStrategy(int);
+    method public void setOrientation(int);
+    method public void setReverseLayout(boolean);
+    method public void setSpanCount(int);
+    field public static final deprecated int GAP_HANDLING_LAZY = 1; // 0x1
+    field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
+    field public static final int GAP_HANDLING_NONE = 0; // 0x0
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final java.lang.String TAG = "StaggeredGridLayoutManager";
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class StaggeredGridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+    method public final int getSpanIndex();
+    method public boolean isFullSpan();
+    method public void setFullSpan(boolean);
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+}
+
+package android.support.v7.widget.helper {
+
+  public class ItemTouchHelper extends android.support.v7.widget.RecyclerView.ItemDecoration implements android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener {
+    ctor public ItemTouchHelper(android.support.v7.widget.helper.ItemTouchHelper.Callback);
+    method public void attachToRecyclerView(android.support.v7.widget.RecyclerView);
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+    method public void startDrag(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void startSwipe(android.support.v7.widget.RecyclerView.ViewHolder);
+    field public static final int ACTION_STATE_DRAG = 2; // 0x2
+    field public static final int ACTION_STATE_IDLE = 0; // 0x0
+    field public static final int ACTION_STATE_SWIPE = 1; // 0x1
+    field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
+    field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
+    field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
+    field public static final int DOWN = 2; // 0x2
+    field public static final int END = 32; // 0x20
+    field public static final int LEFT = 4; // 0x4
+    field public static final int RIGHT = 8; // 0x8
+    field public static final int START = 16; // 0x10
+    field public static final int UP = 1; // 0x1
+  }
+
+  public static abstract class ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.Callback();
+    method public boolean canDropOver(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ViewHolder chooseDropTarget(android.support.v7.widget.RecyclerView.ViewHolder, java.util.List<android.support.v7.widget.RecyclerView.ViewHolder>, int, int);
+    method public void clearView(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int convertToAbsoluteDirection(int, int);
+    method public static int convertToRelativeDirection(int, int);
+    method public long getAnimationDuration(android.support.v7.widget.RecyclerView, int, float, float);
+    method public int getBoundingBoxMargin();
+    method public static android.support.v7.widget.helper.ItemTouchUIUtil getDefaultUIUtil();
+    method public float getMoveThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public abstract int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public float getSwipeThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int interpolateOutOfBoundsScroll(android.support.v7.widget.RecyclerView, int, int, int, long);
+    method public boolean isItemViewSwipeEnabled();
+    method public boolean isLongPressDragEnabled();
+    method public static int makeFlag(int, int);
+    method public static int makeMovementFlags(int, int);
+    method public void onChildDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public void onChildDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public abstract boolean onMove(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onMoved(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int);
+    method public void onSelectedChanged(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    method public abstract void onSwiped(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
+    field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
+  }
+
+  public static abstract class ItemTouchHelper.SimpleCallback extends android.support.v7.widget.helper.ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.SimpleCallback(int, int);
+    method public int getDragDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public int getSwipeDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setDefaultDragDirs(int);
+    method public void setDefaultSwipeDirs(int);
+  }
+
+  public static abstract interface ItemTouchHelper.ViewDropHandler {
+    method public abstract void prepareForDrop(android.view.View, android.view.View, int, int);
+  }
+
+  public abstract interface ItemTouchUIUtil {
+    method public abstract void clearView(android.view.View);
+    method public abstract void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public abstract void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public abstract void onSelected(android.view.View);
+  }
+
+}
+
+package android.support.v7.widget.util {
+
+  public abstract class SortedListAdapterCallback extends android.support.v7.util.SortedList.Callback {
+    ctor public SortedListAdapterCallback(android.support.v7.widget.RecyclerView.Adapter);
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+}
+
diff --git a/v7/recyclerview/api/current.txt b/v7/recyclerview/api/current.txt
index e37956e..1f91036 100644
--- a/v7/recyclerview/api/current.txt
+++ b/v7/recyclerview/api/current.txt
@@ -110,7 +110,7 @@
 
 package android.support.v7.widget {
 
-  public class DefaultItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+  public class DefaultItemAnimator extends android.support.v7.widget.SimpleItemAnimator {
     ctor public DefaultItemAnimator();
     method public boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
     method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
@@ -378,48 +378,57 @@
 
   public static abstract class RecyclerView.ItemAnimator {
     ctor public RecyclerView.ItemAnimator();
-    method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
-    method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
-    method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public abstract boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
     method public final void dispatchAnimationsFinished();
-    method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
-    method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
-    method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
     method public abstract void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
     method public abstract void endAnimations();
     method public long getAddDuration();
     method public long getChangeDuration();
     method public long getMoveDuration();
     method public long getRemoveDuration();
-    method public boolean getSupportsChangeAnimations();
     method public abstract boolean isRunning();
     method public final boolean isRunning(android.support.v7.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener);
-    method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
-    method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
-    method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
-    method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+    method public void onAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder, int, java.util.List<java.lang.Object>);
     method public abstract void runPendingAnimations();
     method public void setAddDuration(long);
     method public void setChangeDuration(long);
     method public void setMoveDuration(long);
     method public void setRemoveDuration(long);
-    method public void setSupportsChangeAnimations(boolean);
+    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+    field public static final int FLAG_CHANGED = 2; // 0x2
+    field public static final int FLAG_INVALIDATED = 4; // 0x4
+    field public static final int FLAG_MOVED = 2048; // 0x800
+    field public static final int FLAG_REMOVED = 8; // 0x8
+  }
+
+  public static abstract class RecyclerView.ItemAnimator.AdapterChanges implements java.lang.annotation.Annotation {
   }
 
   public static abstract interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
     method public abstract void onAnimationsFinished();
   }
 
+  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder, int);
+    field public int bottom;
+    field public int changeFlags;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
   public static abstract class RecyclerView.ItemDecoration {
     ctor public RecyclerView.ItemDecoration();
     method public deprecated void getItemOffsets(android.graphics.Rect, int, android.support.v7.widget.RecyclerView);
@@ -670,7 +679,6 @@
     method public int getTargetScrollPosition();
     method public boolean hasTargetScrollPosition();
     method public boolean isPreLayout();
-    method public void onViewIgnored(android.support.v7.widget.RecyclerView.ViewHolder);
     method public void put(int, java.lang.Object);
     method public void remove(int);
     method public boolean willRunPredictiveAnimations();
@@ -699,6 +707,36 @@
     ctor public RecyclerViewAccessibilityDelegate(android.support.v7.widget.RecyclerView);
   }
 
+  public abstract class SimpleItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+    ctor public SimpleItemAnimator();
+    method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public boolean getSupportsChangeAnimations();
+    method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+    method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+    method public void setSupportsChangeAnimations(boolean);
+  }
+
   public class StaggeredGridLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager {
     ctor public StaggeredGridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
     ctor public StaggeredGridLayoutManager(int, int);
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index 25b686d..c9f1a22 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -78,6 +78,17 @@
     artifacts.add('archives', sourcesJarTask);
 }
 
+// TODO make this generic for all projects
+afterEvaluate {
+    def originalTask = tasks['packageDebugAndroidTest']
+    tasks['assembleDebugAndroidTest'].doLast {
+        copy {
+            from(originalTask.outputFile)
+            into(rootProject.ext.testApkDistOut)
+        }
+    }
+}
+
 uploadArchives {
     repositories {
         mavenDeployer {
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java b/v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java
new file mode 100644
index 0000000..559bc6b
--- /dev/null
+++ b/v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import junit.framework.TestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.Pair;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
+import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+
+@SuppressWarnings("ConstantConditions")
+@RunWith(JUnit4.class)
+public class ViewInfoStoreTest extends TestCase {
+    ViewInfoStore mStore;
+    LoggingProcessCallback mCallback;
+    @Before
+    public void prepare() {
+        mStore = new ViewInfoStore();
+        mCallback = new LoggingProcessCallback();
+    }
+
+    @Test
+    public void addToPreLayout() {
+        RecyclerView.ViewHolder vh = new MockViewHolder();
+        MockInfo info = new MockInfo();
+        mStore.addToPreLayout(vh, info);
+        assertSame(info, find(vh, FLAG_PRE));
+        assertTrue(mStore.isInPreLayout(vh));
+        mStore.removeViewHolder(vh);
+        assertFalse(mStore.isInPreLayout(vh));
+    }
+
+    @Test
+    public void addToPostLayout() {
+        RecyclerView.ViewHolder vh = new MockViewHolder();
+        MockInfo info = new MockInfo();
+        mStore.addToPostLayout(vh, info);
+        assertSame(info, find(vh, FLAG_POST));
+        mStore.removeViewHolder(vh);
+        assertNull(find(vh, FLAG_POST));
+    }
+
+    @Test
+    public void popFromPreLayout() {
+        assertEquals(0, sizeOf(FLAG_PRE));
+        RecyclerView.ViewHolder vh = new MockViewHolder();
+        MockInfo info = new MockInfo();
+        mStore.addToPreLayout(vh, info);
+        assertSame(info, mStore.popFromPreLayout(vh));
+        assertNull(mStore.popFromPreLayout(vh));
+    }
+
+    @Test
+    public void addToOldChangeHolders() {
+        RecyclerView.ViewHolder vh = new MockViewHolder();
+        mStore.addToOldChangeHolders(1, vh);
+        assertSame(vh, mStore.getFromOldChangeHolders(1));
+        mStore.removeViewHolder(vh);
+        assertNull(mStore.getFromOldChangeHolders(1));
+    }
+
+    @Test
+    public void appearListTests() {
+        RecyclerView.ViewHolder vh = new MockViewHolder();
+        RecyclerView.ItemAnimator.ItemHolderInfo info = new MockInfo();
+        mStore.addToAppearedInPreLayoutHolders(vh, info);
+        assertEquals(1, sizeOf(FLAG_APPEAR));
+        RecyclerView.ViewHolder vh2 = new MockViewHolder();
+        mStore.addToAppearedInPreLayoutHolders(vh2, info);
+        assertEquals(2, sizeOf(FLAG_APPEAR));
+        mStore.removeViewHolder(vh2);
+        assertEquals(1, sizeOf(FLAG_APPEAR));
+    }
+
+    @Test
+    public void disappearListTest() {
+        RecyclerView.ViewHolder vh = new MockViewHolder();
+        mStore.addToDisappearedInLayout(vh);
+        assertEquals(1, sizeOf(FLAG_DISAPPEARED));
+        mStore.addToDisappearedInLayout(vh);
+        assertEquals(1, sizeOf(FLAG_DISAPPEARED));
+        RecyclerView.ViewHolder vh2 = new MockViewHolder();
+        mStore.addToDisappearedInLayout(vh2);
+        assertEquals(2, sizeOf(FLAG_DISAPPEARED));
+        mStore.removeViewHolder(vh2);
+        assertEquals(1, sizeOf(FLAG_DISAPPEARED));
+        mStore.removeFromDisappearedInLayout(vh);
+        assertEquals(0, sizeOf(FLAG_DISAPPEARED));
+    }
+
+    @Test
+    public void processAppear() {
+        ViewHolder vh = new MockViewHolder();
+        MockInfo info = new MockInfo();
+        mStore.addToPostLayout(vh, info);
+        mStore.process(mCallback);
+        assertEquals(new Pair<>(null, info), mCallback.appeared.get(vh));
+        assertTrue(mCallback.disappeared.isEmpty());
+        assertTrue(mCallback.unused.isEmpty());
+        assertTrue(mCallback.persistent.isEmpty());
+    }
+
+    @Test
+    public void processDisappearNormal() {
+        ViewHolder vh = new MockViewHolder();
+        MockInfo info = new MockInfo();
+        mStore.addToPreLayout(vh, info);
+        mStore.process(mCallback);
+        assertEquals(new Pair<>(info, null), mCallback.disappeared.get(vh));
+        assertTrue(mCallback.appeared.isEmpty());
+        assertTrue(mCallback.unused.isEmpty());
+        assertTrue(mCallback.persistent.isEmpty());
+    }
+
+    @Test
+    public void processDisappearMissingLayout() {
+        ViewHolder vh = new MockViewHolder();
+        MockInfo info = new MockInfo();
+        mStore.addToPreLayout(vh, info);
+        mStore.addToDisappearedInLayout(vh);
+        mStore.process(mCallback);
+        assertEquals(new Pair<>(info, null), mCallback.disappeared.get(vh));
+        assertTrue(mCallback.appeared.isEmpty());
+        assertTrue(mCallback.unused.isEmpty());
+        assertTrue(mCallback.persistent.isEmpty());
+    }
+
+    @Test
+    public void processDisappearMoveOut() {
+        ViewHolder vh = new MockViewHolder();
+        MockInfo pre = new MockInfo();
+        MockInfo post = new MockInfo();
+        mStore.addToPreLayout(vh, pre);
+        mStore.addToDisappearedInLayout(vh);
+        mStore.addToPostLayout(vh, post);
+        mStore.process(mCallback);
+        assertEquals(new Pair<>(pre, post), mCallback.disappeared.get(vh));
+        assertTrue(mCallback.appeared.isEmpty());
+        assertTrue(mCallback.unused.isEmpty());
+        assertTrue(mCallback.persistent.isEmpty());
+    }
+
+    @Test
+    public void processDisappearAppear() {
+        ViewHolder vh = new MockViewHolder();
+        MockInfo pre = new MockInfo();
+        MockInfo post = new MockInfo();
+        mStore.addToPreLayout(vh, pre);
+        mStore.addToDisappearedInLayout(vh);
+        mStore.addToPostLayout(vh, post);
+        mStore.removeFromDisappearedInLayout(vh);
+        mStore.process(mCallback);
+        assertTrue(mCallback.disappeared.isEmpty());
+        assertTrue(mCallback.appeared.isEmpty());
+        assertTrue(mCallback.unused.isEmpty());
+        assertEquals(mCallback.persistent.get(vh), new Pair<>(pre, post));
+    }
+
+    static class MockViewHolder extends RecyclerView.ViewHolder {
+        public MockViewHolder() {
+            super(new View(null));
+        }
+    }
+
+    static class MockInfo extends RecyclerView.ItemAnimator.ItemHolderInfo {
+
+    }
+
+    private int sizeOf(int flags) {
+        int cnt = 0;
+        final int size = mStore.mLayoutHolderMap.size();
+        for (int i = 0; i < size; i ++) {
+            ViewInfoStore.InfoRecord record = mStore.mLayoutHolderMap.valueAt(i);
+            if ((record.flags & flags) != 0) {
+                cnt ++;
+            }
+        }
+        return cnt;
+    }
+
+    private RecyclerView.ItemAnimator.ItemHolderInfo find(RecyclerView.ViewHolder viewHolder,
+            int flags) {
+        final int size = mStore.mLayoutHolderMap.size();
+        for (int i = 0; i < size; i ++) {
+            ViewInfoStore.InfoRecord record = mStore.mLayoutHolderMap.valueAt(i);
+            RecyclerView.ViewHolder holder = mStore.mLayoutHolderMap.keyAt(i);
+            if ((record.flags & flags) != 0 && holder == viewHolder) {
+                if (flags == FLAG_PRE || flags == FLAG_APPEAR) {
+                    return record.preInfo;
+                } else if (flags == FLAG_POST) {
+                    return record.postInfo;
+                }
+                throw new UnsupportedOperationException("don't know this flag");
+            }
+        }
+        return null;
+    }
+
+    private static class LoggingProcessCallback implements ViewInfoStore.ProcessCallback {
+        final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> disappeared = new HashMap<>();
+        final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> appeared = new HashMap<>();
+        final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> persistent = new HashMap<>();
+        final List<ViewHolder> unused = new ArrayList<>();
+        @Override
+        public void processDisappeared(ViewHolder viewHolder,
+                ItemHolderInfo preInfo,
+                @Nullable ItemHolderInfo postInfo) {
+            assertNotNull(preInfo);
+            assertFalse(disappeared.containsKey(viewHolder));
+            disappeared.put(viewHolder, new Pair<>(preInfo, postInfo));
+        }
+
+        @Override
+        public void processAppeared(ViewHolder viewHolder,
+                @Nullable ItemHolderInfo preInfo, @NonNull ItemHolderInfo info) {
+            assertNotNull(info);
+            assertFalse(appeared.containsKey(viewHolder));
+            appeared.put(viewHolder, new Pair<>(preInfo, info));
+        }
+
+        @Override
+        public void processPersistent(ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+            assertFalse(persistent.containsKey(viewHolder));
+            assertNotNull(preInfo);
+            assertNotNull(postInfo);
+            persistent.put(viewHolder, new Pair<>(preInfo, postInfo));
+        }
+
+        @Override
+        public void unused(ViewHolder holder) {
+            unused.add(holder);
+        }
+    }
+
+}
diff --git a/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java b/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
index 51f99bb..49efcf9 100644
--- a/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
+++ b/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
@@ -18,10 +18,11 @@
 
 import android.os.Handler;
 import android.os.Looper;
+import android.support.v4.content.ParallelExecutorCompat;
 import android.util.Log;
 
 import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 class MessageThreadUtil<T> implements ThreadUtil<T> {
 
@@ -83,7 +84,8 @@
     public BackgroundCallback<T> getBackgroundProxy(final BackgroundCallback<T> callback) {
         return new BackgroundCallback<T>() {
             final private MessageQueue mQueue = new MessageQueue();
-            final private Executor mExecutor = Executors.newSingleThreadExecutor();
+            final private Executor mExecutor = ParallelExecutorCompat.getParallelExecutor();
+            AtomicBoolean mBackgroundRunning = new AtomicBoolean(false);
 
             private static final int REFRESH = 1;
             private static final int UPDATE_RANGE = 2;
@@ -114,42 +116,51 @@
 
             private void sendMessage(SyncQueueItem msg) {
                 mQueue.sendMessage(msg);
-                mExecutor.execute(mBackgroundRunnable);
+                maybeExecuteBackgroundRunnable();
             }
 
             private void sendMessageAtFrontOfQueue(SyncQueueItem msg) {
                 mQueue.sendMessageAtFrontOfQueue(msg);
-                mExecutor.execute(mBackgroundRunnable);
+                maybeExecuteBackgroundRunnable();
+            }
+
+            private void maybeExecuteBackgroundRunnable() {
+                if (mBackgroundRunning.compareAndSet(false, true)) {
+                    mExecutor.execute(mBackgroundRunnable);
+                }
             }
 
             private Runnable mBackgroundRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    SyncQueueItem msg = mQueue.next();
-                    if (msg == null) {
-                        return;
+                    while (true) {
+                        SyncQueueItem msg = mQueue.next();
+                        if (msg == null) {
+                            break;
+                        }
+                        switch (msg.what) {
+                            case REFRESH:
+                                mQueue.removeMessages(REFRESH);
+                                callback.refresh(msg.arg1);
+                                break;
+                            case UPDATE_RANGE:
+                                mQueue.removeMessages(UPDATE_RANGE);
+                                mQueue.removeMessages(LOAD_TILE);
+                                callback.updateRange(
+                                        msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
+                                break;
+                            case LOAD_TILE:
+                                callback.loadTile(msg.arg1, msg.arg2);
+                                break;
+                            case RECYCLE_TILE:
+                                //noinspection unchecked
+                                callback.recycleTile((TileList.Tile<T>) msg.data);
+                                break;
+                            default:
+                                Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
+                        }
                     }
-                    switch (msg.what) {
-                        case REFRESH:
-                            mQueue.removeMessages(REFRESH);
-                            callback.refresh(msg.arg1);
-                            break;
-                        case UPDATE_RANGE:
-                            mQueue.removeMessages(UPDATE_RANGE);
-                            mQueue.removeMessages(LOAD_TILE);
-                            callback.updateRange(
-                                    msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
-                            break;
-                        case LOAD_TILE:
-                            callback.loadTile(msg.arg1, msg.arg2);
-                            break;
-                        case RECYCLE_TILE:
-                            //noinspection unchecked
-                            callback.recycleTile((TileList.Tile<T>) msg.data);
-                            break;
-                        default:
-                            Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
-                    }
+                    mBackgroundRunning.set(false);
                 }
             };
         };
diff --git a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
index e9feab8..9220c5e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
@@ -67,6 +67,8 @@
 
     final OpReorderer mOpReorderer;
 
+    private int mExistingUpdateTypes = 0;
+
     AdapterHelper(Callback callback) {
         this(callback, false);
     }
@@ -85,6 +87,7 @@
     void reset() {
         recycleUpdateOpsAndClearList(mPendingUpdates);
         recycleUpdateOpsAndClearList(mPostponedList);
+        mExistingUpdateTypes = 0;
     }
 
     void preProcess() {
@@ -119,6 +122,7 @@
             mCallback.onDispatchSecondPass(mPostponedList.get(i));
         }
         recycleUpdateOpsAndClearList(mPostponedList);
+        mExistingUpdateTypes = 0;
     }
 
     private void applyMove(UpdateOp op) {
@@ -457,6 +461,10 @@
         return mPendingUpdates.size() > 0;
     }
 
+    boolean hasAnyUpdateTypes(int updateTypes) {
+        return (mExistingUpdateTypes & updateTypes) != 0;
+    }
+
     int findPositionOffset(int position) {
         return findPositionOffset(position, 0);
     }
@@ -495,6 +503,7 @@
      */
     boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
         mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
+        mExistingUpdateTypes |= UpdateOp.UPDATE;
         return mPendingUpdates.size() == 1;
     }
 
@@ -503,6 +512,7 @@
      */
     boolean onItemRangeInserted(int positionStart, int itemCount) {
         mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
+        mExistingUpdateTypes |= UpdateOp.ADD;
         return mPendingUpdates.size() == 1;
     }
 
@@ -511,6 +521,7 @@
      */
     boolean onItemRangeRemoved(int positionStart, int itemCount) {
         mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
+        mExistingUpdateTypes |= UpdateOp.REMOVE;
         return mPendingUpdates.size() == 1;
     }
 
@@ -525,6 +536,7 @@
             throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
         }
         mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
+        mExistingUpdateTypes |= UpdateOp.MOVE;
         return mPendingUpdates.size() == 1;
     }
 
@@ -561,6 +573,7 @@
             }
         }
         recycleUpdateOpsAndClearList(mPendingUpdates);
+        mExistingUpdateTypes = 0;
     }
 
     public int applyPendingUpdatesToPosition(int position) {
@@ -604,13 +617,13 @@
      */
     static class UpdateOp {
 
-        static final int ADD = 0;
+        static final int ADD = 1;
 
-        static final int REMOVE = 1;
+        static final int REMOVE = 1 << 1;
 
-        static final int UPDATE = 2;
+        static final int UPDATE = 1 << 2;
 
-        static final int MOVE = 3;
+        static final int MOVE = 1 << 3;
 
         static final int POOL_SIZE = 30;
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java b/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
index 66ebab5..0afa405 100644
--- a/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
@@ -208,8 +208,8 @@
         for (int i = 0; i < count; i++) {
             final View view = mHiddenViews.get(i);
             RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
-            if (holder.getLayoutPosition() == position && !holder.isInvalid() &&
-                    (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
+            if (holder.getLayoutPosition() == position && !holder.isInvalid() && !holder.isRemoved()
+                    && (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
                 return view;
             }
         }
@@ -339,6 +339,25 @@
         }
     }
 
+    /**
+     * Moves a child view from hidden list to regular list.
+     * Calling this method should probably be followed by a detach, otherwise, it will suddenly
+     * show up in LayoutManager's children list.
+     *
+     * @param view The hidden View to unhide
+     */
+    void unhide(View view) {
+        final int offset = mCallback.indexOfChild(view);
+        if (offset < 0) {
+            throw new IllegalArgumentException("view is not a child, cannot hide " + view);
+        }
+        if (!mBucket.get(offset)) {
+            throw new RuntimeException("trying to unhide a view that was not hidden" + view);
+        }
+        mBucket.clear(offset);
+        unhideViewInternal(view);
+    }
+
     @Override
     public String toString() {
         return mBucket.toString() + ", hidden list:" + mHiddenViews.size();
diff --git a/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java b/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
index fa45d84..0809efe 100644
--- a/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
+++ b/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
@@ -32,23 +32,22 @@
  *
  * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
  */
-public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
+public class DefaultItemAnimator extends SimpleItemAnimator {
     private static final boolean DEBUG = false;
 
-    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
-    private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
-    private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
-    private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<ChangeInfo>();
+    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
+    private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
+    private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
+    private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
 
-    private ArrayList<ArrayList<ViewHolder>> mAdditionsList =
-            new ArrayList<ArrayList<ViewHolder>>();
-    private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<ArrayList<MoveInfo>>();
-    private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<ArrayList<ChangeInfo>>();
+    private ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
+    private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
+    private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
 
-    private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
-    private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
-    private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
-    private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<ViewHolder>();
+    private ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
+    private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
+    private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
+    private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
 
     private static class MoveInfo {
         public ViewHolder holder;
@@ -110,7 +109,7 @@
         mPendingRemovals.clear();
         // Next, move stuff
         if (movesPending) {
-            final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
+            final ArrayList<MoveInfo> moves = new ArrayList<>();
             moves.addAll(mPendingMoves);
             mMovesList.add(moves);
             mPendingMoves.clear();
@@ -134,7 +133,7 @@
         }
         // Next, change stuff, to run in parallel with move animations
         if (changesPending) {
-            final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
+            final ArrayList<ChangeInfo> changes = new ArrayList<>();
             changes.addAll(mPendingChanges);
             mChangesList.add(changes);
             mPendingChanges.clear();
@@ -157,7 +156,7 @@
         }
         // Next, add stuff
         if (additionsPending) {
-            final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
+            final ArrayList<ViewHolder> additions = new ArrayList<>();
             additions.addAll(mPendingAdditions);
             mAdditionsList.add(additions);
             mPendingAdditions.clear();
@@ -310,6 +309,11 @@
     @Override
     public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
             int fromX, int fromY, int toX, int toY) {
+        if (oldHolder == newHolder) {
+            // Don't know how to run change animations when the same view holder is re-used.
+            // run a move animation to handle position changes.
+            return animateMove(oldHolder, fromX, fromY, toX, toY);
+        }
         final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
         final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
         final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
@@ -320,7 +324,7 @@
         ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
         ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
         ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
-        if (newHolder != null && newHolder.itemView != null) {
+        if (newHolder != null) {
             // carry over translation values
             resetAnimation(newHolder);
             ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
@@ -479,21 +483,25 @@
         }
 
         // animations should be ended by the cancel above.
+        //noinspection PointlessBooleanExpression,ConstantConditions
         if (mRemoveAnimations.remove(item) && DEBUG) {
             throw new IllegalStateException("after animation is cancelled, item should not be in "
                     + "mRemoveAnimations list");
         }
 
+        //noinspection PointlessBooleanExpression,ConstantConditions
         if (mAddAnimations.remove(item) && DEBUG) {
             throw new IllegalStateException("after animation is cancelled, item should not be in "
                     + "mAddAnimations list");
         }
 
+        //noinspection PointlessBooleanExpression,ConstantConditions
         if (mChangeAnimations.remove(item) && DEBUG) {
             throw new IllegalStateException("after animation is cancelled, item should not be in "
                     + "mChangeAnimations list");
         }
 
+        //noinspection PointlessBooleanExpression,ConstantConditions
         if (mMoveAnimations.remove(item) && DEBUG) {
             throw new IllegalStateException("after animation is cancelled, item should not be in "
                     + "mMoveAnimations list");
@@ -633,5 +641,5 @@
 
         @Override
         public void onAnimationCancel(View view) {}
-    };
+    }
 }
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index 910405a..7dcaea0 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -303,11 +303,31 @@
         if (state.getItemCount() > 0 && !state.isPreLayout()) {
             ensureAnchorIsInFirstSpan(recycler, state, anchorInfo);
         }
+        ensureViewSet();
+    }
+
+    private void ensureViewSet() {
         if (mSet == null || mSet.length != mSpanCount) {
             mSet = new View[mSpanCount];
         }
     }
 
+    @Override
+    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        updateMeasurements();
+        ensureViewSet();
+        return super.scrollHorizontallyBy(dx, recycler, state);
+    }
+
+    @Override
+    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        updateMeasurements();
+        ensureViewSet();
+        return super.scrollVerticallyBy(dy, recycler, state);
+    }
+
     private void ensureAnchorIsInFirstSpan(RecyclerView.Recycler recycler, RecyclerView.State state,
                                            AnchorInfo anchorInfo) {
         int span = getSpanIndex(recycler, state, anchorInfo.mPosition);
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index 632b05c..b896902 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -2035,7 +2035,10 @@
         }
     }
 
-    static class SavedState implements Parcelable {
+    /**
+     * @hide
+     */
+    public static class SavedState implements Parcelable {
 
         int mAnchorPosition;
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index d21f046..57684f8 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -16,7 +16,6 @@
 
 
 package android.support.v7.widget;
-
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.Observable;
@@ -27,11 +26,12 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.annotation.CallSuper;
 import android.os.SystemClock;
+import android.support.annotation.CallSuper;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.os.TraceCompat;
-import android.support.v4.util.ArrayMap;
 import android.support.v4.view.InputDeviceCompat;
 import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.NestedScrollingChild;
@@ -62,6 +62,8 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Interpolator;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
@@ -70,6 +72,7 @@
 
 import static android.support.v7.widget.AdapterHelper.Callback;
 import static android.support.v7.widget.AdapterHelper.UpdateOp;
+import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
 
 /**
  * A flexible view for providing a limited window into a large data set.
@@ -239,11 +242,22 @@
 
     private SavedState mPendingSavedState;
 
+    /**
+     * Handles adapter updates
+     */
     AdapterHelper mAdapterHelper;
 
+    /**
+     * Handles abstraction between LayoutManager children and RecyclerView children
+     */
     ChildHelper mChildHelper;
 
     /**
+     * Keeps data about views to be used for animations
+     */
+    final ViewInfoStore mViewInfoStore = new ViewInfoStore();
+
+    /**
      * Prior to L, there is no way to query this variable which is why we override the setter and
      * track it here.
      */
@@ -257,26 +271,15 @@
      */
     private final Runnable mUpdateChildViewsRunnable = new Runnable() {
         public void run() {
-            if (!mFirstLayoutComplete) {
+            if (!mFirstLayoutComplete || isLayoutRequested()) {
                 // a layout request will happen, we should not do layout here.
                 return;
             }
-            if (mDataSetHasChangedAfterLayout) {
-                TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
-                dispatchLayout();
-                TraceCompat.endSection();
-            } else if (mAdapterHelper.hasPendingUpdates()) {
-                TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
-                eatRequestLayout();
-                mAdapterHelper.preProcess();
-                if (!mLayoutRequestEaten) {
-                    // We run this after pre-processing is complete so that ViewHolders have their
-                    // final adapter positions. No need to run it if a layout is already requested.
-                    rebindUpdatedViewHolders();
-                }
-                resumeRequestLayout(true);
-                TraceCompat.endSection();
+            if (mLayoutFrozen) {
+                mLayoutRequestEaten = true;
+                return; //we'll process updates when ice age ends.
             }
+            consumePendingUpdateOperations();
         }
     };
 
@@ -401,6 +404,44 @@
         }
     };
 
+    /**
+     * The callback to convert view info diffs into animations.
+     */
+    private final ViewInfoStore.ProcessCallback mViewInfoProcessCallback =
+            new ViewInfoStore.ProcessCallback() {
+        @Override
+        public void processDisappeared(ViewHolder viewHolder, ItemHolderInfo info,
+                ItemHolderInfo postInfo) {
+            mRecycler.unscrapView(viewHolder);
+            animateDisappearance(viewHolder, info, postInfo);
+        }
+        @Override
+        public void processAppeared(ViewHolder viewHolder,
+                ItemHolderInfo preInfo, ItemHolderInfo info) {
+            animateAppearance(viewHolder, preInfo, info);
+        }
+
+        @Override
+        public void processPersistent(ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+            viewHolder.setIsRecyclable(false);
+            if (mDataSetHasChangedAfterLayout) {
+                // since it was rebound, use change instead as we'll be mapping them from
+                // stable ids. If stable ids were false, we would not be running any
+                // animations
+                if (mItemAnimator.animateChange(viewHolder, viewHolder, preInfo, postInfo)) {
+                    postAnimationRunner();
+                }
+            } else if (mItemAnimator.animatePersistence(viewHolder, preInfo, postInfo)) {
+                postAnimationRunner();
+            }
+        }
+        @Override
+        public void unused(ViewHolder viewHolder) {
+            mLayout.removeAndRecycleView(viewHolder.itemView, mRecycler);
+        }
+    };
+
     public RecyclerView(Context context) {
         this(context, null);
     }
@@ -1338,8 +1379,8 @@
 
     @Override
     public void scrollTo(int x, int y) {
-        throw new UnsupportedOperationException(
-                "RecyclerView does not support scrolling to an absolute position.");
+        Log.w(TAG, "RecyclerView does not support scrolling to an absolute position. "
+                + "Use scrollToPosition instead");
     }
 
     @Override
@@ -1368,7 +1409,59 @@
      * This method consumes all deferred changes to avoid that case.
      */
     private void consumePendingUpdateOperations() {
-        mUpdateChildViewsRunnable.run();
+        if (!mFirstLayoutComplete) {
+            // a layout request will happen, we should not do layout here.
+            return;
+        }
+        if (mDataSetHasChangedAfterLayout) {
+            TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
+            dispatchLayout();
+            TraceCompat.endSection();
+            return;
+        }
+        if (!mAdapterHelper.hasPendingUpdates()) {
+            return;
+        }
+
+        // if it is only an item change (no add-remove-notifyDataSetChanged) we can check if any
+        // of the visible items is affected and if not, just ignore the change.
+        if (mAdapterHelper.hasAnyUpdateTypes(UpdateOp.UPDATE) && !mAdapterHelper
+                .hasAnyUpdateTypes(UpdateOp.ADD | UpdateOp.REMOVE | UpdateOp.MOVE)) {
+            TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
+            eatRequestLayout();
+            mAdapterHelper.preProcess();
+            if (!mLayoutRequestEaten) {
+                if (hasUpdatedView()) {
+                    dispatchLayout();
+                } else {
+                    // no need to layout, clean state
+                    mAdapterHelper.consumePostponedUpdates();
+                }
+            }
+            resumeRequestLayout(true);
+            TraceCompat.endSection();
+        } else if (mAdapterHelper.hasPendingUpdates()) {
+            TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
+            dispatchLayout();
+            TraceCompat.endSection();
+        }
+    }
+
+    /**
+     * @return True if an existing view holder needs to be updated
+     */
+    private boolean hasUpdatedView() {
+        final int childCount = mChildHelper.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
+            if (holder == null || holder.shouldIgnore()) {
+                continue;
+            }
+            if (holder.isUpdated()) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -1400,27 +1493,7 @@
                 unconsumedY = y - consumedY;
             }
             TraceCompat.endSection();
-            if (supportsChangeAnimations()) {
-                // Fix up shadow views used by changing animations
-                int count = mChildHelper.getChildCount();
-                for (int i = 0; i < count; i++) {
-                    View view = mChildHelper.getChildAt(i);
-                    ViewHolder holder = getChildViewHolder(view);
-                    if (holder != null && holder.mShadowingHolder != null) {
-                        ViewHolder shadowingHolder = holder.mShadowingHolder;
-                        View shadowingView = shadowingHolder != null ? shadowingHolder.itemView : null;
-                        if (shadowingView != null) {
-                            int left = view.getLeft();
-                            int top = view.getTop();
-                            if (left != shadowingView.getLeft() || top != shadowingView.getTop()) {
-                                shadowingView.layout(left, top,
-                                        left + shadowingView.getWidth(),
-                                        top + shadowingView.getHeight());
-                            }
-                        }
-                    }
-                }
-            }
+            repositionShadowingViews();
             onExitLayoutOrScroll();
             resumeRequestLayout(false);
         }
@@ -2001,6 +2074,7 @@
             mLayout.dispatchDetachedFromWindow(this, mRecycler);
         }
         removeCallbacks(mItemAnimatorRunner);
+        mViewInfoStore.onDetach();
     }
 
     /**
@@ -2164,6 +2238,9 @@
                     setScrollState(SCROLL_STATE_DRAGGING);
                 }
 
+                // Clear the nested offsets
+                mNestedOffsets[0] = mNestedOffsets[1] = 0;
+
                 int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE;
                 if (canScrollHorizontally) {
                     nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL;
@@ -2203,10 +2280,6 @@
                         startScroll = true;
                     }
                     if (startScroll) {
-                        final ViewParent parent = getParent();
-                        if (parent != null) {
-                            parent.requestDisallowInterceptTouchEvent(true);
-                        }
                         setScrollState(SCROLL_STATE_DRAGGING);
                     }
                 }
@@ -2332,10 +2405,6 @@
                         startScroll = true;
                     }
                     if (startScroll) {
-                        final ViewParent parent = getParent();
-                        if (parent != null) {
-                            parent.requestDisallowInterceptTouchEvent(true);
-                        }
                         setScrollState(SCROLL_STATE_DRAGGING);
                     }
                 }
@@ -2662,10 +2731,6 @@
         return mItemAnimator;
     }
 
-    private boolean supportsChangeAnimations() {
-        return mItemAnimator != null && mItemAnimator.getSupportsChangeAnimations();
-    }
-
     /**
      * Post a runnable to the next frame to run pending item animations. Only the first such
      * request will be posted, governed by the mPostedAnimatorRunner flag.
@@ -2703,8 +2768,7 @@
         } else {
             mAdapterHelper.consumeUpdatesInOnePass();
         }
-        boolean animationTypeSupported = (mItemsAddedOrRemoved && !mItemsChanged) ||
-                (mItemsAddedOrRemoved || (mItemsChanged && supportsChangeAnimations()));
+        boolean animationTypeSupported = mItemsAddedOrRemoved || mItemsChanged;
         mState.mRunSimpleAnimations = mFirstLayoutComplete && mItemAnimator != null &&
                 (mDataSetHasChangedAfterLayout || animationTypeSupported ||
                         mLayout.mRequestedSimpleAnimations) &&
@@ -2730,11 +2794,14 @@
      * The overall approach figures out what items exist before/after layout and
      * infers one of the five above states for each of the items. Then the animations
      * are set up accordingly:
-     * PERSISTENT views are moved ({@link ItemAnimator#animateMove(ViewHolder, int, int, int, int)})
-     * REMOVED views are removed ({@link ItemAnimator#animateRemove(ViewHolder)})
-     * ADDED views are added ({@link ItemAnimator#animateAdd(ViewHolder)})
-     * DISAPPEARING views are moved off screen
-     * APPEARING views are moved on screen
+     * PERSISTENT views are animated via
+     * {@link ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+     * DISAPPEARING views are animated via
+     * {@link ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+     * APPEARING views are animated via
+     * {@link ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+     * and changed views are animated via
+     * {@link ItemAnimator#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)}.
      */
     void dispatchLayout() {
         if (mAdapter == null) {
@@ -2745,33 +2812,42 @@
             Log.e(TAG, "No layout manager attached; skipping layout");
             return;
         }
-        mState.mDisappearingViewsInLayoutPass.clear();
+        mViewInfoStore.clear();
         eatRequestLayout();
         onEnterLayoutOrScroll();
 
         processAdapterUpdatesAndSetAnimationFlags();
-
-        mState.mOldChangedHolders = mState.mRunSimpleAnimations && mItemsChanged
-                && supportsChangeAnimations() ? new ArrayMap<Long, ViewHolder>() : null;
+        mState.mTrackOldChangeHolders = mState.mRunSimpleAnimations && mItemsChanged;
         mItemsAddedOrRemoved = mItemsChanged = false;
-        ArrayMap<View, Rect> appearingViewInitialBounds = null;
         mState.mInPreLayout = mState.mRunPredictiveAnimations;
         mState.mItemCount = mAdapter.getItemCount();
         findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);
 
         if (mState.mRunSimpleAnimations) {
             // Step 0: Find out where all non-removed items are, pre-layout
-            mState.mPreLayoutHolderMap.clear();
-            mState.mPostLayoutHolderMap.clear();
             int count = mChildHelper.getChildCount();
             for (int i = 0; i < count; ++i) {
                 final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                 if (holder.shouldIgnore() || (holder.isInvalid() && !mAdapter.hasStableIds())) {
                     continue;
                 }
-                final View view = holder.itemView;
-                mState.mPreLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
-                        view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+                final ItemHolderInfo animationInfo = mItemAnimator
+                        .recordPreLayoutInformation(mState, holder,
+                                ItemAnimator.buildAdapterChangeFlagsForAnimations(holder),
+                                holder.getUnmodifiedPayloads());
+                mViewInfoStore.addToPreLayout(holder, animationInfo);
+                if (mState.mTrackOldChangeHolders && holder.isUpdated() && !holder.isRemoved()
+                        && !holder.shouldIgnore() && !holder.isInvalid()) {
+                    long key = getChangedHolderKey(holder);
+                    // This is NOT the only place where a ViewHolder is added to old change holders
+                    // list. There is another case where:
+                    //    * A VH is currently hidden but not deleted
+                    //    * The hidden item is changed in the adapter
+                    //    * Layout manager decides to layout the item in the pre-Layout pass (step1)
+                    // When this case is detected, RV will un-hide that view and add to the old
+                    // change holders list.
+                    mViewInfoStore.addToOldChangeHolders(key, holder);
+                }
             }
         }
         if (mState.mRunPredictiveAnimations) {
@@ -2782,42 +2858,32 @@
 
             // Save old positions so that LayoutManager can run its mapping logic.
             saveOldPositions();
-            // processAdapterUpdatesAndSetAnimationFlags already run pre-layout animations.
-            if (mState.mOldChangedHolders != null) {
-                int count = mChildHelper.getChildCount();
-                for (int i = 0; i < count; ++i) {
-                    final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
-                    if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
-                        long key = getChangedHolderKey(holder);
-                        mState.mOldChangedHolders.put(key, holder);
-                        mState.mPreLayoutHolderMap.remove(holder);
-                    }
-                }
-            }
-
             final boolean didStructureChange = mState.mStructureChanged;
             mState.mStructureChanged = false;
             // temporarily disable flag because we are asking for previous layout
             mLayout.onLayoutChildren(mRecycler, mState);
             mState.mStructureChanged = didStructureChange;
 
-            appearingViewInitialBounds = new ArrayMap<View, Rect>();
             for (int i = 0; i < mChildHelper.getChildCount(); ++i) {
-                boolean found = false;
-                View child = mChildHelper.getChildAt(i);
-                if (getChildViewHolderInt(child).shouldIgnore()) {
+                final View child = mChildHelper.getChildAt(i);
+                final ViewHolder viewHolder = getChildViewHolderInt(child);
+                if (viewHolder.shouldIgnore()) {
                     continue;
                 }
-                for (int j = 0; j < mState.mPreLayoutHolderMap.size(); ++j) {
-                    ViewHolder holder = mState.mPreLayoutHolderMap.keyAt(j);
-                    if (holder.itemView == child) {
-                        found = true;
-                        break;
+                if (!mViewInfoStore.isInPreLayout(viewHolder)) {
+                    int flags = ItemAnimator.buildAdapterChangeFlagsForAnimations(viewHolder);
+                    boolean wasHidden = viewHolder
+                            .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+                    if (!wasHidden) {
+                        flags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;
                     }
-                }
-                if (!found) {
-                    appearingViewInitialBounds.put(child, new Rect(child.getLeft(), child.getTop(),
-                            child.getRight(), child.getBottom()));
+                    final ItemHolderInfo animationInfo = mItemAnimator.recordPreLayoutInformation(
+                            mState, viewHolder, flags, viewHolder.getUnmodifiedPayloads());
+                    if (wasHidden) {
+                        recordAnimationInfoIfBouncedHiddenView(viewHolder, animationInfo);
+                    } else {
+                        mViewInfoStore.addToAppearedInPreLayoutHolders(viewHolder, animationInfo);
+                    }
                 }
             }
             // we don't process disappearing list because they may re-appear in post layout pass.
@@ -2825,19 +2891,6 @@
             mAdapterHelper.consumePostponedUpdates();
         } else {
             clearOldPositions();
-            // in case pre layout did run but we decided not to run predictive animations.
-            mAdapterHelper.consumeUpdatesInOnePass();
-            if (mState.mOldChangedHolders != null) {
-                int count = mChildHelper.getChildCount();
-                for (int i = 0; i < count; ++i) {
-                    final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
-                    if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
-                        long key = getChangedHolderKey(holder);
-                        mState.mOldChangedHolders.put(key, holder);
-                        mState.mPreLayoutHolderMap.remove(holder);
-                    }
-                }
-            }
         }
         mState.mItemCount = mAdapter.getItemCount();
         mState.mDeletedInvisibleItemCountSincePreviousLayout = 0;
@@ -2853,112 +2906,64 @@
         mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;
 
         if (mState.mRunSimpleAnimations) {
-            // Step 3: Find out where things are now, post-layout
-            ArrayMap<Long, ViewHolder> newChangedHolders = mState.mOldChangedHolders != null ?
-                    new ArrayMap<Long, ViewHolder>() : null;
+            // Step 3: Find out where things are now, and process change animations.
             int count = mChildHelper.getChildCount();
             for (int i = 0; i < count; ++i) {
                 ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                 if (holder.shouldIgnore()) {
                     continue;
                 }
-                final View view = holder.itemView;
                 long key = getChangedHolderKey(holder);
-                if (newChangedHolders != null && mState.mOldChangedHolders.get(key) != null) {
-                    newChangedHolders.put(key, holder);
+                final ItemHolderInfo animationInfo = mItemAnimator
+                        .recordPostLayoutInformation(mState, holder);
+                ViewHolder oldChangeViewHolder = mViewInfoStore.getFromOldChangeHolders(key);
+                if (oldChangeViewHolder != null && !oldChangeViewHolder.shouldIgnore()) {
+                    // run a change animation
+                    final ItemHolderInfo preInfo = mViewInfoStore.popFromPreLayout(
+                            oldChangeViewHolder);
+                    animateChange(oldChangeViewHolder, holder, preInfo, animationInfo);
                 } else {
-                    mState.mPostLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
-                            view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+                    mViewInfoStore.addToPostLayout(holder, animationInfo);
                 }
             }
-            processDisappearingList(appearingViewInitialBounds);
-            // Step 4: Animate DISAPPEARING and REMOVED items
-            int preLayoutCount = mState.mPreLayoutHolderMap.size();
-            for (int i = preLayoutCount - 1; i >= 0; i--) {
-                ViewHolder itemHolder = mState.mPreLayoutHolderMap.keyAt(i);
-                if (!mState.mPostLayoutHolderMap.containsKey(itemHolder)) {
-                    ItemHolderInfo disappearingItem = mState.mPreLayoutHolderMap.valueAt(i);
-                    mState.mPreLayoutHolderMap.removeAt(i);
 
-                    View disappearingItemView = disappearingItem.holder.itemView;
-                    mRecycler.unscrapView(disappearingItem.holder);
-                    animateDisappearance(disappearingItem);
-                }
-            }
-            // Step 5: Animate APPEARING and ADDED items
-            int postLayoutCount = mState.mPostLayoutHolderMap.size();
-            if (postLayoutCount > 0) {
-                for (int i = postLayoutCount - 1; i >= 0; i--) {
-                    ViewHolder itemHolder = mState.mPostLayoutHolderMap.keyAt(i);
-                    ItemHolderInfo info = mState.mPostLayoutHolderMap.valueAt(i);
-                    if ((mState.mPreLayoutHolderMap.isEmpty() ||
-                            !mState.mPreLayoutHolderMap.containsKey(itemHolder))) {
-                        mState.mPostLayoutHolderMap.removeAt(i);
-                        Rect initialBounds = (appearingViewInitialBounds != null) ?
-                                appearingViewInitialBounds.get(itemHolder.itemView) : null;
-                        animateAppearance(itemHolder, initialBounds,
-                                info.left, info.top);
-                    }
-                }
-            }
-            // Step 6: Animate PERSISTENT items
-            count = mState.mPostLayoutHolderMap.size();
-            for (int i = 0; i < count; ++i) {
-                ViewHolder postHolder = mState.mPostLayoutHolderMap.keyAt(i);
-                ItemHolderInfo postInfo = mState.mPostLayoutHolderMap.valueAt(i);
-                ItemHolderInfo preInfo = mState.mPreLayoutHolderMap.get(postHolder);
-                if (preInfo != null && postInfo != null) {
-                    if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
-                        postHolder.setIsRecyclable(false);
-                        if (DEBUG) {
-                            Log.d(TAG, "PERSISTENT: " + postHolder +
-                                    " with view " + postHolder.itemView);
-                        }
-                        if (mItemAnimator.animateMove(postHolder,
-                                preInfo.left, preInfo.top, postInfo.left, postInfo.top)) {
-                            postAnimationRunner();
-                        }
-                    }
-                }
-            }
-            // Step 7: Animate CHANGING items
-            count = mState.mOldChangedHolders != null ? mState.mOldChangedHolders.size() : 0;
-            // traverse reverse in case view gets recycled while we are traversing the list.
-            for (int i = count - 1; i >= 0; i--) {
-                long key = mState.mOldChangedHolders.keyAt(i);
-                ViewHolder oldHolder = mState.mOldChangedHolders.get(key);
-                View oldView = oldHolder.itemView;
-                if (oldHolder.shouldIgnore()) {
-                    continue;
-                }
-                // We probably don't need this check anymore since these views are removed from
-                // the list if they are recycled.
-                if (mRecycler.mChangedScrap != null &&
-                        mRecycler.mChangedScrap.contains(oldHolder)) {
-                    animateChange(oldHolder, newChangedHolders.get(key));
-                } else if (DEBUG) {
-                    Log.e(TAG, "cannot find old changed holder in changed scrap :/" + oldHolder);
-                }
-            }
+            // Step 4: Process view info lists and trigger animations
+            mViewInfoStore.process(mViewInfoProcessCallback);
         }
         resumeRequestLayout(false);
         mLayout.removeAndRecycleScrapInt(mRecycler);
         mState.mPreviousLayoutItemCount = mState.mItemCount;
         mDataSetHasChangedAfterLayout = false;
         mState.mRunSimpleAnimations = false;
+
         mState.mRunPredictiveAnimations = false;
         onExitLayoutOrScroll();
         mLayout.mRequestedSimpleAnimations = false;
         if (mRecycler.mChangedScrap != null) {
             mRecycler.mChangedScrap.clear();
         }
-        mState.mOldChangedHolders = null;
-
+        mViewInfoStore.clear();
         if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) {
             dispatchOnScrolled(0, 0);
         }
     }
 
+    /**
+     * Records the animation information for a view holder that was bounced from hidden list. It
+     * also clears the bounce back flag.
+     */
+    private void recordAnimationInfoIfBouncedHiddenView(ViewHolder viewHolder,
+            ItemHolderInfo animationInfo) {
+        // looks like this view bounced back from hidden list!
+        viewHolder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+        if (mState.mTrackOldChangeHolders && viewHolder.isUpdated()
+                && !viewHolder.isRemoved() && !viewHolder.shouldIgnore()) {
+            long key = getChangedHolderKey(viewHolder);
+            mViewInfoStore.addToOldChangeHolders(key, viewHolder);
+        }
+        mViewInfoStore.addToPreLayout(viewHolder, animationInfo);
+    }
+
     private void findMinMaxChildLayoutPositions(int[] into) {
         final int count = mChildHelper.getChildCount();
         if (count == 0) {
@@ -3026,114 +3031,35 @@
         return mAdapter.hasStableIds() ? holder.getItemId() : holder.mPosition;
     }
 
-    /**
-     * A LayoutManager may want to layout a view just to animate disappearance.
-     * This method handles those views and triggers remove animation on them.
-     */
-    private void processDisappearingList(ArrayMap<View, Rect> appearingViews) {
-        final List<View> disappearingList = mState.mDisappearingViewsInLayoutPass;
-        for (int i = disappearingList.size() - 1; i >= 0; i --) {
-            View view = disappearingList.get(i);
-            ViewHolder vh = getChildViewHolderInt(view);
-            final ItemHolderInfo info = mState.mPreLayoutHolderMap.remove(vh);
-            if (!mState.isPreLayout()) {
-                mState.mPostLayoutHolderMap.remove(vh);
-            }
-            if (appearingViews.remove(view) != null) {
-                mLayout.removeAndRecycleView(view, mRecycler);
-                continue;
-            }
-            if (info != null) {
-                animateDisappearance(info);
-            } else {
-                // let it disappear from the position it becomes visible
-                animateDisappearance(new ItemHolderInfo(vh, view.getLeft(), view.getTop(),
-                        view.getRight(), view.getBottom()));
-            }
-        }
-        disappearingList.clear();
-    }
-
-    private void animateAppearance(ViewHolder itemHolder, Rect beforeBounds, int afterLeft,
-            int afterTop) {
-        View newItemView = itemHolder.itemView;
-        if (beforeBounds != null &&
-                (beforeBounds.left != afterLeft || beforeBounds.top != afterTop)) {
-            // slide items in if before/after locations differ
-            itemHolder.setIsRecyclable(false);
-            if (DEBUG) {
-                Log.d(TAG, "APPEARING: " + itemHolder + " with view " + newItemView);
-            }
-            if (mItemAnimator.animateMove(itemHolder,
-                    beforeBounds.left, beforeBounds.top,
-                    afterLeft, afterTop)) {
-                postAnimationRunner();
-            }
-        } else {
-            if (DEBUG) {
-                Log.d(TAG, "ADDED: " + itemHolder + " with view " + newItemView);
-            }
-            itemHolder.setIsRecyclable(false);
-            if (mItemAnimator.animateAdd(itemHolder)) {
-                postAnimationRunner();
-            }
+    private void animateAppearance(@NonNull ViewHolder itemHolder,
+            @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
+        itemHolder.setIsRecyclable(false);
+        if (mItemAnimator.animateAppearance(itemHolder, preLayoutInfo, postLayoutInfo)) {
+            postAnimationRunner();
         }
     }
 
-    private void animateDisappearance(ItemHolderInfo disappearingItem) {
-        View disappearingItemView = disappearingItem.holder.itemView;
-        addAnimatingView(disappearingItem.holder);
-        int oldLeft = disappearingItem.left;
-        int oldTop = disappearingItem.top;
-        int newLeft = disappearingItemView.getLeft();
-        int newTop = disappearingItemView.getTop();
-        if (!disappearingItem.holder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
-            disappearingItem.holder.setIsRecyclable(false);
-            disappearingItemView.layout(newLeft, newTop,
-                    newLeft + disappearingItemView.getWidth(),
-                    newTop + disappearingItemView.getHeight());
-            if (DEBUG) {
-                Log.d(TAG, "DISAPPEARING: " + disappearingItem.holder +
-                        " with view " + disappearingItemView);
-            }
-            if (mItemAnimator.animateMove(disappearingItem.holder, oldLeft, oldTop,
-                    newLeft, newTop)) {
-                postAnimationRunner();
-            }
-        } else {
-            if (DEBUG) {
-                Log.d(TAG, "REMOVED: " + disappearingItem.holder +
-                        " with view " + disappearingItemView);
-            }
-            disappearingItem.holder.setIsRecyclable(false);
-            if (mItemAnimator.animateRemove(disappearingItem.holder)) {
-                postAnimationRunner();
-            }
+    private void animateDisappearance(@NonNull ViewHolder holder,
+            @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
+        addAnimatingView(holder);
+        holder.setIsRecyclable(false);
+        if (mItemAnimator.animateDisappearance(holder, preLayoutInfo, postLayoutInfo)) {
+            postAnimationRunner();
         }
     }
 
-    private void animateChange(ViewHolder oldHolder, ViewHolder newHolder) {
+    private void animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder,
+            @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
         oldHolder.setIsRecyclable(false);
-        addAnimatingView(oldHolder);
-        oldHolder.mShadowedHolder = newHolder;
-        mRecycler.unscrapView(oldHolder);
-        if (DEBUG) {
-            Log.d(TAG, "CHANGED: " + oldHolder + " with view " + oldHolder.itemView);
-        }
-        final int fromLeft = oldHolder.itemView.getLeft();
-        final int fromTop = oldHolder.itemView.getTop();
-        final int toLeft, toTop;
-        if (newHolder == null || newHolder.shouldIgnore()) {
-            toLeft = fromLeft;
-            toTop = fromTop;
-        } else {
-            toLeft = newHolder.itemView.getLeft();
-            toTop = newHolder.itemView.getTop();
+        if (oldHolder != newHolder) {
+            oldHolder.mShadowedHolder = newHolder;
+            // old holder should disappear after animation ends
+            addAnimatingView(oldHolder);
+            mRecycler.unscrapView(oldHolder);
             newHolder.setIsRecyclable(false);
             newHolder.mShadowingHolder = oldHolder;
         }
-        if(mItemAnimator.animateChange(oldHolder, newHolder,
-                fromLeft, fromTop, toLeft, toTop)) {
+        if (mItemAnimator.animateChange(oldHolder, newHolder, preInfo, postInfo)) {
             postAnimationRunner();
         }
     }
@@ -3405,9 +3331,6 @@
                 // ViewHolders have their final positions assigned.
                 holder.addFlags(ViewHolder.FLAG_UPDATE);
                 holder.addChangePayload(payload);
-                if (supportsChangeAnimations()) {
-                    holder.addFlags(ViewHolder.FLAG_CHANGED);
-                }
                 // lp cannot be null since we get ViewHolder from it.
                 ((LayoutParams) child.getLayoutParams()).mInsetsDirty = true;
             }
@@ -3415,36 +3338,8 @@
         mRecycler.viewRangeUpdate(positionStart, itemCount);
     }
 
-    void rebindUpdatedViewHolders() {
-        final int childCount = mChildHelper.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
-            // validate type is correct
-            if (holder == null || holder.shouldIgnore()) {
-                continue;
-            }
-            if (holder.isRemoved() || holder.isInvalid()) {
-                requestLayout();
-            } else if (holder.needsUpdate()) {
-                final int type = mAdapter.getItemViewType(holder.mPosition);
-                if (holder.getItemViewType() == type) {
-                    // Binding an attached view will request a layout if needed.
-                    if (!holder.isChanged() || !supportsChangeAnimations()) {
-                        mAdapter.bindViewHolder(holder, holder.mPosition);
-                    } else {
-                        // Don't rebind changed holders if change animations are enabled.
-                        // We want the old contents for the animation and will get a new
-                        // holder for the new contents.
-                        requestLayout();
-                    }
-                } else {
-                    // binding to a new view will need re-layout anyways. We can as well trigger
-                    // it here so that it happens during layout
-                    requestLayout();
-                    break;
-                }
-            }
-        }
+    private boolean canReuseUpdatedViewHolder(ViewHolder viewHolder) {
+        return mItemAnimator == null || mItemAnimator.canReuseUpdatedViewHolder(viewHolder);
     }
 
     private void setDataSetChangedAfterLayout() {
@@ -3913,25 +3808,8 @@
                         overscrollY = dy - vresult;
                     }
                     TraceCompat.endSection();
-                    if (supportsChangeAnimations()) {
-                        // Fix up shadow views used by changing animations
-                        int count = mChildHelper.getChildCount();
-                        for (int i = 0; i < count; i++) {
-                            View view = mChildHelper.getChildAt(i);
-                            ViewHolder holder = getChildViewHolder(view);
-                            if (holder != null && holder.mShadowingHolder != null) {
-                                View shadowingView = holder.mShadowingHolder.itemView;
-                                int left = view.getLeft();
-                                int top = view.getTop();
-                                if (left != shadowingView.getLeft() ||
-                                        top != shadowingView.getTop()) {
-                                    shadowingView.layout(left, top,
-                                            left + shadowingView.getWidth(),
-                                            top + shadowingView.getHeight());
-                                }
-                            }
-                        }
-                    }
+                    repositionShadowingViews();
+
                     onExitLayoutOrScroll();
                     resumeRequestLayout(false);
 
@@ -4097,6 +3975,26 @@
 
     }
 
+    private void repositionShadowingViews() {
+        // Fix up shadow views used by change animations
+        int count = mChildHelper.getChildCount();
+        for (int i = 0; i < count; i++) {
+            View view = mChildHelper.getChildAt(i);
+            ViewHolder holder = getChildViewHolder(view);
+            if (holder != null && holder.mShadowingHolder != null) {
+                View shadowingView = holder.mShadowingHolder.itemView;
+                int left = view.getLeft();
+                int top = view.getTop();
+                if (left != shadowingView.getLeft() ||
+                        top != shadowingView.getTop()) {
+                    shadowingView.layout(left, top,
+                            left + shadowingView.getWidth(),
+                            top + shadowingView.getHeight());
+                }
+            }
+        }
+    }
+
     private class RecyclerViewDataObserver extends AdapterDataObserver {
         @Override
         public void onChanged() {
@@ -4343,7 +4241,11 @@
             // if it is a removed holder, nothing to verify since we cannot ask adapter anymore
             // if it is not removed, verify the type and id.
             if (holder.isRemoved()) {
-                return true;
+                if (DEBUG && !mState.isPreLayout()) {
+                    throw new IllegalStateException("should not receive a removed view unelss it"
+                            + " is pre layout");
+                }
+                return mState.isPreLayout();
             }
             if (holder.mPosition < 0 || holder.mPosition >= mAdapter.getItemCount()) {
                 throw new IndexOutOfBoundsException("Inconsistency detected. Invalid view holder "
@@ -4554,6 +4456,23 @@
                     }
                 }
             }
+
+            // This is very ugly but the only place we can grab this information
+            // before the View is rebound and returned to the LayoutManager for post layout ops.
+            // We don't need this in pre-layout since the VH is not updated by the LM.
+            if (fromScrap && !mState.isPreLayout() && holder
+                    .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST)) {
+                holder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+                if (mState.mRunSimpleAnimations) {
+                    int changeFlags = ItemAnimator
+                            .buildAdapterChangeFlagsForAnimations(holder);
+                    changeFlags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;
+                    final ItemHolderInfo info = mItemAnimator.recordPreLayoutInformation(mState,
+                            holder, changeFlags, holder.getUnmodifiedPayloads());
+                    recordAnimationInfoIfBouncedHiddenView(holder, info);
+                }
+            }
+
             boolean bound = false;
             if (mState.isPreLayout() && holder.isBound()) {
                 // do not update unless we absolutely have to.
@@ -4730,8 +4649,8 @@
                         holder);
             }
             if (forceRecycle || holder.isRecyclable()) {
-                if (!holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED |
-                        ViewHolder.FLAG_CHANGED | ViewHolder.FLAG_UPDATE)) {
+                if (!holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED
+                        | ViewHolder.FLAG_UPDATE)) {
                     // Retire oldest cached view
                     final int cachedViewSize = mCachedViews.size();
                     if (cachedViewSize == mViewCacheMax && cachedViewSize > 0) {
@@ -4752,7 +4671,7 @@
             }
             // even if the holder is not removed, we still call this method so that it is removed
             // from view holder lists.
-            mState.onViewRecycled(holder);
+            mViewInfoStore.removeViewHolder(holder);
             if (!cached && !recycled && transientStatePreventsRecycling) {
                 holder.mOwnerRecyclerView = null;
             }
@@ -4773,6 +4692,7 @@
         void quickRecycleScrapView(View view) {
             final ViewHolder holder = getChildViewHolderInt(view);
             holder.mScrapContainer = null;
+            holder.mInChangeScrap = false;
             holder.clearReturnedFromScrapFlag();
             recycleViewHolderInternal(holder);
         }
@@ -4788,18 +4708,20 @@
          */
         void scrapView(View view) {
             final ViewHolder holder = getChildViewHolderInt(view);
-            holder.setScrapContainer(this);
-            if (!holder.isChanged() || !supportsChangeAnimations()) {
+            if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
+                    || !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {
                 if (holder.isInvalid() && !holder.isRemoved() && !mAdapter.hasStableIds()) {
                     throw new IllegalArgumentException("Called scrap view with an invalid view."
                             + " Invalid views cannot be reused from scrap, they should rebound from"
                             + " recycler pool.");
                 }
+                holder.setScrapContainer(this, false);
                 mAttachedScrap.add(holder);
             } else {
                 if (mChangedScrap == null) {
                     mChangedScrap = new ArrayList<ViewHolder>();
                 }
+                holder.setScrapContainer(this, true);
                 mChangedScrap.add(holder);
             }
         }
@@ -4811,12 +4733,13 @@
          * until it is explicitly removed and recycled.</p>
          */
         void unscrapView(ViewHolder holder) {
-            if (!holder.isChanged() || !supportsChangeAnimations() || mChangedScrap == null) {
-                mAttachedScrap.remove(holder);
-            } else {
+            if (holder.mInChangeScrap) {
                 mChangedScrap.remove(holder);
+            } else {
+                mAttachedScrap.remove(holder);
             }
             holder.mScrapContainer = null;
+            holder.mInChangeScrap = false;
             holder.clearReturnedFromScrapFlag();
         }
 
@@ -4830,6 +4753,9 @@
 
         void clearScrap() {
             mAttachedScrap.clear();
+            if (mChangedScrap != null) {
+                mChangedScrap.clear();
+            }
         }
 
         ViewHolder getChangedScrapViewForPosition(int position) {
@@ -4894,8 +4820,20 @@
             if (!dryRun) {
                 View view = mChildHelper.findHiddenNonRemovedView(position, type);
                 if (view != null) {
-                    // ending the animation should cause it to get recycled before we reuse it
-                    mItemAnimator.endAnimation(getChildViewHolder(view));
+                    // This View is good to be used. We just need to unhide, detach and move to the
+                    // scrap list.
+                    final ViewHolder vh = getChildViewHolderInt(view);
+                    mChildHelper.unhide(view);
+                    int layoutIndex = mChildHelper.indexOfChild(view);
+                    if (layoutIndex == RecyclerView.NO_POSITION) {
+                        throw new IllegalStateException("layout index should not be -1 after "
+                                + "unhiding a view:" + vh);
+                    }
+                    mChildHelper.detachViewFromParent(layoutIndex);
+                    scrapView(view);
+                    vh.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP
+                            | ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+                    return vh;
                 }
             }
 
@@ -4943,6 +4881,8 @@
                         }
                         return holder;
                     } else if (!dryRun) {
+                        // if we are running animations, it is actually better to keep it in scrap
+                        // but this would force layout manager to lay it out which would be bad.
                         // Recycle this scrap. Type mismatch.
                         mAttachedScrap.remove(i);
                         removeDetachedView(holder.itemView, false);
@@ -4977,7 +4917,7 @@
                 mAdapter.onViewRecycled(holder);
             }
             if (mState != null) {
-                mState.onViewRecycled(holder);
+                mViewInfoStore.removeViewHolder(holder);
             }
             if (DEBUG) Log.d(TAG, "dispatchViewRecycled: " + holder);
         }
@@ -6276,14 +6216,14 @@
             final ViewHolder holder = getChildViewHolderInt(child);
             if (disappearing || holder.isRemoved()) {
                 // these views will be hidden at the end of the layout pass.
-                mRecyclerView.mState.addToDisappearingList(child);
+                mRecyclerView.mViewInfoStore.addToDisappearedInLayout(holder);
             } else {
                 // This may look like unnecessary but may happen if layout manager supports
                 // predictive layouts and adapter removed then re-added the same item.
                 // In this case, added version will be visible in the post layout (because add is
                 // deferred) but RV will still bind it to the same View.
                 // So if a View re-appears in post layout pass, remove it from disappearing list.
-                mRecyclerView.mState.removeFromDisappearingList(child);
+                mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(holder);
             }
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (holder.wasReturnedFromScrap() || holder.isScrap()) {
@@ -6485,9 +6425,9 @@
         public void attachView(View child, int index, LayoutParams lp) {
             ViewHolder vh = getChildViewHolderInt(child);
             if (vh.isRemoved()) {
-                mRecyclerView.mState.addToDisappearingList(child);
+                mRecyclerView.mViewInfoStore.addToDisappearedInLayout(vh);
             } else {
-                mRecyclerView.mState.removeFromDisappearingList(child);
+                mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(vh);
             }
             mChildHelper.attachViewToParent(child, index, lp, vh.isRemoved());
             if (DISPATCH_TEMP_DETACH)  {
@@ -6785,7 +6725,7 @@
             }
             final ViewHolder vh = getChildViewHolderInt(view);
             vh.addFlags(ViewHolder.FLAG_IGNORE);
-            mRecyclerView.mState.onViewIgnored(vh);
+            mRecyclerView.mViewInfoStore.removeViewHolder(vh);
         }
 
         /**
@@ -6827,7 +6767,7 @@
                 }
                 return;
             }
-            if (viewHolder.isInvalid() && !viewHolder.isRemoved() && !viewHolder.isChanged() &&
+            if (viewHolder.isInvalid() && !viewHolder.isRemoved() &&
                     !mRecyclerView.mAdapter.hasStableIds()) {
                 removeViewAt(index);
                 recycler.recycleViewHolderInternal(viewHolder);
@@ -8236,12 +8176,6 @@
         static final int FLAG_RETURNED_FROM_SCRAP = 1 << 5;
 
         /**
-         * This ViewHolder's contents have changed. This flag is used as an indication that
-         * change animations may be used, if supported by the ItemAnimator.
-         */
-        static final int FLAG_CHANGED = 1 << 6;
-
-        /**
          * This ViewHolder is fully managed by the LayoutManager. We do not scrap, recycle or remove
          * it unless LayoutManager is replaced.
          * It is still fully visible to the LayoutManager.
@@ -8268,6 +8202,31 @@
          */
         static final int FLAG_ADAPTER_FULLUPDATE = 1 << 10;
 
+        /**
+         * Used by ItemAnimator when a ViewHolder's position changes
+         */
+        static final int FLAG_MOVED = 1 << 11;
+
+        /**
+         * Used by ItemAnimator when a ViewHolder appears in pre-layout
+         */
+        static final int FLAG_APPEARED_IN_PRE_LAYOUT = 1 << 12;
+
+        /**
+         * Used when a ViewHolder starts the layout pass as a hidden ViewHolder but is re-used from
+         * hidden list (as if it was scrap) without being recycled in between.
+         *
+         * When a ViewHolder is hidden, there are 2 paths it can be re-used:
+         *   a) Animation ends, view is recycled and used from the recycle pool.
+         *   b) LayoutManager asks for the View for that position while the ViewHolder is hidden.
+         *
+         * This flag is used to represent "case b" where the ViewHolder is reused without being
+         * recycled (thus "bounced" from the hidden list). This state requires special handling
+         * because the ViewHolder must be added to pre layout maps for animations as if it was
+         * already there.
+         */
+        static final int FLAG_BOUNCED_FROM_HIDDEN_LIST = 1 << 13;
+
         private int mFlags;
 
         private static final List<Object> FULLUPDATE_PAYLOADS = Collections.EMPTY_LIST;
@@ -8280,6 +8239,8 @@
         // If non-null, view is currently considered scrap and may be reused for other data by the
         // scrap container.
         private Recycler mScrapContainer = null;
+        // Keeps whether this ViewHolder lives in Change scrap or Attached scrap
+        private boolean mInChangeScrap = false;
 
         // Saves isImportantForAccessibility value for the view item while it's in hidden state and
         // marked as unimportant for accessibility.
@@ -8460,8 +8421,9 @@
             mFlags = mFlags & ~FLAG_IGNORE;
         }
 
-        void setScrapContainer(Recycler recycler) {
+        void setScrapContainer(Recycler recycler, boolean isChangeScrap) {
             mScrapContainer = recycler;
+            mInChangeScrap = isChangeScrap;
         }
 
         boolean isInvalid() {
@@ -8472,10 +8434,6 @@
             return (mFlags & FLAG_UPDATE) != 0;
         }
 
-        boolean isChanged() {
-            return (mFlags & FLAG_CHANGED) != 0;
-        }
-
         boolean isBound() {
             return (mFlags & FLAG_BOUND) != 0;
         }
@@ -8579,16 +8537,18 @@
             final StringBuilder sb = new StringBuilder("ViewHolder{" +
                     Integer.toHexString(hashCode()) + " position=" + mPosition + " id=" + mItemId +
                     ", oldPos=" + mOldPosition + ", pLpos:" + mPreLayoutPosition);
-            if (isScrap()) sb.append(" scrap");
+            if (isScrap()) {
+                sb.append(" scrap ")
+                        .append(mInChangeScrap ? "[changeScrap]" : "[attachedScrap]");
+            }
             if (isInvalid()) sb.append(" invalid");
             if (!isBound()) sb.append(" unbound");
             if (needsUpdate()) sb.append(" update");
             if (isRemoved()) sb.append(" removed");
             if (shouldIgnore()) sb.append(" ignored");
-            if (isChanged()) sb.append(" changed");
             if (isTmpDetached()) sb.append(" tmpDetached");
             if (!isRecyclable()) sb.append(" not recyclable(" + mIsRecyclableCount + ")");
-            if (isAdapterPositionUnknown()) sb.append("undefined adapter position");
+            if (isAdapterPositionUnknown()) sb.append(" undefined adapter position");
 
             if (itemView.getParent() == null) sb.append(" no parent");
             sb.append("}");
@@ -8651,6 +8611,10 @@
         private boolean doesTransientStatePreventRecycling() {
             return (mFlags & FLAG_NOT_RECYCLABLE) == 0 && ViewCompat.hasTransientState(itemView);
         }
+
+        boolean isUpdated() {
+            return (mFlags & FLAG_UPDATE) != 0;
+        }
     }
 
     private int getAdapterPositionFor(ViewHolder viewHolder) {
@@ -8785,7 +8749,7 @@
          * @return true if the item the view corresponds to was changed in the data set
          */
         public boolean isItemChanged() {
-            return mViewHolder.isChanged();
+            return mViewHolder.isUpdated();
         }
 
         /**
@@ -9320,7 +9284,11 @@
         }
     }
 
-    static class SavedState extends android.view.View.BaseSavedState {
+    /**
+     * This is public so that the CREATOR can be access on cold launch.
+     * @hide
+     */
+    public static class SavedState extends android.view.View.BaseSavedState {
 
         Parcelable mLayoutState;
 
@@ -9375,15 +9343,6 @@
     public static class State {
 
         private int mTargetPosition = RecyclerView.NO_POSITION;
-        ArrayMap<ViewHolder, ItemHolderInfo> mPreLayoutHolderMap =
-                new ArrayMap<ViewHolder, ItemHolderInfo>();
-        ArrayMap<ViewHolder, ItemHolderInfo> mPostLayoutHolderMap =
-                new ArrayMap<ViewHolder, ItemHolderInfo>();
-        // nullable
-        ArrayMap<Long, ViewHolder> mOldChangedHolders = new ArrayMap<Long, ViewHolder>();
-
-        // we use this like a set
-        final List<View> mDisappearingViewsInLayoutPass = new ArrayList<View>();
 
         private SparseArray<Object> mData;
 
@@ -9411,6 +9370,8 @@
 
         private boolean mRunPredictiveAnimations = false;
 
+        private boolean mTrackOldChangeHolders = false;
+
         State reset() {
             mTargetPosition = RecyclerView.NO_POSITION;
             if (mData != null) {
@@ -9547,45 +9508,10 @@
                     mItemCount;
         }
 
-        void onViewRecycled(ViewHolder holder) {
-            mPreLayoutHolderMap.remove(holder);
-            mPostLayoutHolderMap.remove(holder);
-            if (mOldChangedHolders != null) {
-                removeFrom(mOldChangedHolders, holder);
-            }
-            mDisappearingViewsInLayoutPass.remove(holder.itemView);
-            // holder cannot be in new list.
-        }
-
-        public void onViewIgnored(ViewHolder holder) {
-            onViewRecycled(holder);
-        }
-
-        private void removeFrom(ArrayMap<Long, ViewHolder> holderMap, ViewHolder holder) {
-            for (int i = holderMap.size() - 1; i >= 0; i --) {
-                if (holder == holderMap.valueAt(i)) {
-                    holderMap.removeAt(i);
-                    return;
-                }
-            }
-        }
-
-        void removeFromDisappearingList(View child) {
-            mDisappearingViewsInLayoutPass.remove(child);
-        }
-
-        void addToDisappearingList(View child) {
-            if (!mDisappearingViewsInLayoutPass.contains(child)) {
-                mDisappearingViewsInLayoutPass.add(child);
-            }
-        }
-
         @Override
         public String toString() {
             return "State{" +
                     "mTargetPosition=" + mTargetPosition +
-                    ", mPreLayoutHolderMap=" + mPreLayoutHolderMap +
-                    ", mPostLayoutHolderMap=" + mPostLayoutHolderMap +
                     ", mData=" + mData +
                     ", mItemCount=" + mItemCount +
                     ", mPreviousLayoutItemCount=" + mPreviousLayoutItemCount +
@@ -9608,71 +9534,21 @@
     private class ItemAnimatorRestoreListener implements ItemAnimator.ItemAnimatorListener {
 
         @Override
-        public void onRemoveFinished(ViewHolder item) {
+        public void onAnimationFinished(ViewHolder item) {
             item.setIsRecyclable(true);
-            if (!removeAnimatingView(item.itemView) && item.isTmpDetached()) {
-                removeDetachedView(item.itemView, false);
-            }
-        }
-
-        @Override
-        public void onAddFinished(ViewHolder item) {
-            item.setIsRecyclable(true);
-            if (!item.shouldBeKeptAsChild()) {
-                removeAnimatingView(item.itemView);
-            }
-        }
-
-        @Override
-        public void onMoveFinished(ViewHolder item) {
-            item.setIsRecyclable(true);
-            if (!item.shouldBeKeptAsChild()) {
-                removeAnimatingView(item.itemView);
-            }
-        }
-
-        @Override
-        public void onChangeFinished(ViewHolder item) {
-            item.setIsRecyclable(true);
-            /**
-             * We check both shadowed and shadowing because a ViewHolder may get both roles at the
-             * same time.
-             *
-             * Assume this flow:
-             * item X is represented by VH_1. Then itemX changes, so we create VH_2 .
-             * RV sets the following and calls item animator:
-             * VH_1.shadowed = VH_2;
-             * VH_1.mChanged = true;
-             * VH_2.shadowing =VH_1;
-             *
-             * Then, before the first change finishes, item changes again so we create VH_3.
-             * RV sets the following and calls item animator:
-             * VH_2.shadowed = VH_3
-             * VH_2.mChanged = true
-             * VH_3.shadowing = VH_2
-             *
-             * Because VH_2 already has an animation, it will be cancelled. At this point VH_2 has
-             * both shadowing and shadowed fields set. Shadowing information is obsolete now
-             * because the first animation where VH_2 is newViewHolder is not valid anymore.
-             * We ended up in this case because VH_2 played both roles. On the other hand,
-             * we DO NOT want to clear its changed flag.
-             *
-             * If second change was simply reverting first change, we would find VH_1 in
-             * {@link Recycler#getScrapViewForPosition(int, int, boolean)} and recycle it before
-             * re-using
-             */
             if (item.mShadowedHolder != null && item.mShadowingHolder == null) { // old vh
                 item.mShadowedHolder = null;
-                item.setFlags(~ViewHolder.FLAG_CHANGED, item.mFlags);
             }
             // always null this because an OldViewHolder can never become NewViewHolder w/o being
             // recycled.
             item.mShadowingHolder = null;
             if (!item.shouldBeKeptAsChild()) {
-                removeAnimatingView(item.itemView);
+                if (!removeAnimatingView(item.itemView) && item.isTmpDetached()) {
+                    removeDetachedView(item.itemView, false);
+                }
             }
         }
-    };
+    }
 
     /**
      * This class defines the animations that take place on items as changes are made
@@ -9680,22 +9556,78 @@
      *
      * Subclasses of ItemAnimator can be used to implement custom animations for actions on
      * ViewHolder items. The RecyclerView will manage retaining these items while they
-     * are being animated, but implementors must call the appropriate "Starting"
-     * ({@link #dispatchRemoveStarting(ViewHolder)}, {@link #dispatchMoveStarting(ViewHolder)},
-     * {@link #dispatchChangeStarting(ViewHolder, boolean)}, or
-     * {@link #dispatchAddStarting(ViewHolder)})
-     * and "Finished" ({@link #dispatchRemoveFinished(ViewHolder)},
-     * {@link #dispatchMoveFinished(ViewHolder)},
-     * {@link #dispatchChangeFinished(ViewHolder, boolean)},
-     * or {@link #dispatchAddFinished(ViewHolder)}) methods when each item animation is
-     * being started and ended.
+     * are being animated, but implementors must call {@link #dispatchAnimationFinished(ViewHolder)}
+     * when a ViewHolder's animation is finished. In other words, there must be a matching
+     * {@link #dispatchAnimationFinished(ViewHolder)} call for each
+     * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) animateAppearance()},
+     * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     * animateChange()}
+     * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) animatePersistence()},
+     * and
+     * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     * animateDisappearance()} call.
      *
-     * <p>By default, RecyclerView uses {@link DefaultItemAnimator}</p>
+     * <p>By default, RecyclerView uses {@link DefaultItemAnimator}.</p>
      *
      * @see #setItemAnimator(ItemAnimator)
      */
+    @SuppressWarnings("UnusedParameters")
     public static abstract class ItemAnimator {
 
+        /**
+         * The Item represented by this ViewHolder is updated.
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_CHANGED = ViewHolder.FLAG_UPDATE;
+
+        /**
+         * The Item represented by this ViewHolder is removed from the adapter.
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_REMOVED = ViewHolder.FLAG_REMOVED;
+
+        /**
+         * Adapter {@link Adapter#notifyDataSetChanged()} has been called and the content
+         * represented by this ViewHolder is invalid.
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_INVALIDATED = ViewHolder.FLAG_INVALID;
+
+        /**
+         * The position of the Item represented by this ViewHolder has been changed. This flag is
+         * not bound to {@link Adapter#notifyItemMoved(int, int)}. It might be set in response to
+         * any adapter change that may have a side effect on this item. (e.g. The item before this
+         * one has been removed from the Adapter).
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_MOVED = ViewHolder.FLAG_MOVED;
+
+        /**
+         * This ViewHolder was not laid out but has been added to the layout in pre-layout state
+         * by the {@link LayoutManager}. This means that the item was already in the Adapter but
+         * invisible and it may become visible in the post layout phase. LayoutManagers may prefer
+         * to add new items in pre-layout to specify their virtual location when they are invisible
+         * (e.g. to specify the item should <i>animate in</i> from below the visible area).
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_APPEARED_IN_PRE_LAYOUT
+                = ViewHolder.FLAG_APPEARED_IN_PRE_LAYOUT;
+
+        /**
+         * The set of flags that might be passed to
+         * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         */
+        @IntDef(flag=true, value={
+                FLAG_CHANGED, FLAG_REMOVED, FLAG_MOVED, FLAG_INVALIDATED,
+                FLAG_APPEARED_IN_PRE_LAYOUT
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface AdapterChanges {}
         private ItemAnimatorListener mListener = null;
         private ArrayList<ItemAnimatorFinishedListener> mFinishedListeners =
                 new ArrayList<ItemAnimatorFinishedListener>();
@@ -9705,8 +9637,6 @@
         private long mMoveDuration = 250;
         private long mChangeDuration = 250;
 
-        private boolean mSupportsChangeAnimations = true;
-
         /**
          * Gets the current duration for which all move animations will run.
          *
@@ -9780,35 +9710,6 @@
         }
 
         /**
-         * Returns whether this ItemAnimator supports animations of change events.
-         *
-         * @return true if change animations are supported, false otherwise
-         */
-        public boolean getSupportsChangeAnimations() {
-            return mSupportsChangeAnimations;
-        }
-
-        /**
-         * Sets whether this ItemAnimator supports animations of item change events.
-         * If you set this property to false, actions on the data set which change the
-         * contents of items will not be animated. What those animations are is left
-         * up to the discretion of the ItemAnimator subclass, in its
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} implementation.
-         * The value of this property is true by default.
-         *
-         * @see Adapter#notifyItemChanged(int)
-         * @see Adapter#notifyItemRangeChanged(int, int)
-         *
-         * @param supportsChangeAnimations true if change animations are supported by
-         * this ItemAnimator, false otherwise. If the property is false, the ItemAnimator
-         * will not receive a call to
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} when changes occur.
-         */
-        public void setSupportsChangeAnimations(boolean supportsChangeAnimations) {
-            mSupportsChangeAnimations = supportsChangeAnimations;
-        }
-
-        /**
          * Internal only:
          * Sets the listener that must be called when the animator is finished
          * animating the item (or immediately if no animation happens). This is set
@@ -9821,219 +9722,255 @@
         }
 
         /**
+         * Called by the RecyclerView before the layout begins. Item animator should record
+         * necessary information about the View before it is potentially rebound, moved or removed.
+         * <p>
+         * The data returned from this method will be passed to the related <code>animate**</code>
+         * methods.
+         * <p>
+         * Note that this method may be called after pre-layout phase if LayoutManager adds new
+         * Views to the layout in pre-layout pass.
+         * <p>
+         * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of
+         * the View and the adapter change flags.
+         *
+         * @param state       The current State of RecyclerView which includes some useful data
+         *                    about the layout that will be calculated.
+         * @param viewHolder  The ViewHolder whose information should be recorded.
+         * @param changeFlags Additional information about what changes happened in the Adapter
+         *                    about the Item represented by this ViewHolder. For instance, if
+         *                    item is deleted from the adapter, {@link #FLAG_REMOVED} will be set.
+         * @param payloads    The payload list that was previously passed to
+         *                    {@link Adapter#notifyItemChanged(int, Object)} or
+         *                    {@link Adapter#notifyItemRangeChanged(int, int, Object)}.
+         *
+         * @return An ItemHolderInfo instance that preserves necessary information about the
+         * ViewHolder. This object will be passed back to related <code>animate**</code> methods
+         * after layout is complete.
+         *
+         * @see #recordPostLayoutInformation(State, ViewHolder)
+         * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animateDisappearance(ViewHolder, ItemHolderInfo)
+         * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         */
+        public @NonNull ItemHolderInfo recordPreLayoutInformation(@NonNull State state,
+                @NonNull ViewHolder viewHolder, @AdapterChanges int changeFlags,
+                @NonNull List<Object> payloads) {
+            return obtainHolderInfo().setFrom(viewHolder);
+        }
+
+        /**
+         * Called by the RecyclerView after the layout is complete. Item animator should record
+         * necessary information about the View's final state.
+         * <p>
+         * The data returned from this method will be passed to the related <code>animate**</code>
+         * methods.
+         * <p>
+         * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of
+         * the View.
+         *
+         * @param state      The current State of RecyclerView which includes some useful data about
+         *                   the layout that will be calculated.
+         * @param viewHolder The ViewHolder whose information should be recorded.
+         *
+         * @return An ItemHolderInfo that preserves necessary information about the ViewHolder.
+         * This object will be passed back to related <code>animate**</code> methods when
+         * RecyclerView decides how items should be animated.
+         *
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         */
+        public @NonNull ItemHolderInfo recordPostLayoutInformation(@NonNull State state,
+                @NonNull ViewHolder viewHolder) {
+            return obtainHolderInfo().setFrom(viewHolder);
+        }
+
+        /**
+         * Called by the RecyclerView when a ViewHolder has disappeared from the layout.
+         * <p>
+         * This means that the View was a child of the LayoutManager when layout started but has
+         * been removed by the LayoutManager. It might have been removed from the adapter or simply
+         * become invisible due to other factors. You can distinguish these two cases by checking
+         * the change flags that were passed to
+         * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * <p>
+         * If LayoutManager supports predictive animations, it might provide a target disappear
+         * location for the View by laying it out in that location. When that happens,
+         * RecyclerView will call {@link #recordPostLayoutInformation(State, ViewHolder)} and the
+         * response of that call will be passed to this method as the <code>postLayoutInfo</code>.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+         * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+         * decides not to animate the view).
+         *
+         * @param viewHolder    The ViewHolder which should be animated
+         * @param preLayoutInfo The information that was returned from
+         *                      {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * @param postLayoutInfo The information that was returned from
+         *                       {@link #recordPostLayoutInformation(State, ViewHolder)}. Might be
+         *                       null if the LayoutManager did not layout the item.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animateDisappearance(@NonNull ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo);
+
+        /**
+         * Called by the RecyclerView when a ViewHolder is added to the layout.
+         * <p>
+         * In detail, this means that the ViewHolder was <b>not</b> a child when the layout started
+         * but has  been added by the LayoutManager. It might be newly added to the adapter or
+         * simply become visible due to other factors.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+         * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+         * decides not to animate the view).
+         *
+         * @param viewHolder     The ViewHolder which should be animated
+         * @param preLayoutInfo  The information that was returned from
+         *                       {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *                       Might be null if Item was just added to the adapter or
+         *                       LayoutManager does not support predictive animations or it could
+         *                       not predict that this ViewHolder will become visible.
+         * @param postLayoutInfo The information that was returned from {@link
+         *                       #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animateAppearance(@NonNull ViewHolder viewHolder,
+                @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+        /**
+         * Called by the RecyclerView when a ViewHolder is present in both before and after the
+         * layout and RecyclerView has not received a {@link Adapter#notifyItemChanged(int)} call
+         * for it or a {@link Adapter#notifyDataSetChanged()} call.
+         * <p>
+         * This ViewHolder still represents the same data that it was representing when the layout
+         * started but its position / size may be changed by the LayoutManager.
+         * <p>
+         * If the Item's layout position didn't change, RecyclerView still calls this method because
+         * it does not track this information (or does not necessarily know that an animation is
+         * not required). Your ItemAnimator should handle this case and if there is nothing to
+         * animate, it should call {@link #dispatchAnimationFinished(ViewHolder)} and return
+         * <code>false</code>.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+         * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+         * decides not to animate the view).
+         *
+         * @param viewHolder     The ViewHolder which should be animated
+         * @param preLayoutInfo  The information that was returned from
+         *                       {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * @param postLayoutInfo The information that was returned from {@link
+         *                       #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animatePersistence(@NonNull ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+        /**
+         * Called by the RecyclerView when an adapter item is present both before and after the
+         * layout and RecyclerView has received a {@link Adapter#notifyItemChanged(int)} call
+         * for it. This method may also be called when
+         * {@link Adapter#notifyDataSetChanged()} is called and adapter has stable ids so that
+         * RecyclerView could still rebind views to the same ViewHolders. If viewType changes when
+         * {@link Adapter#notifyDataSetChanged()} is called, this method <b>will not</b> be called,
+         * instead, {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)} will be
+         * called for the new ViewHolder and the old one will be recycled.
+         * <p>
+         * If this method is called due to a {@link Adapter#notifyDataSetChanged()} call, there is
+         * a good possibility that item contents didn't really change but it is rebound from the
+         * adapter. {@link DefaultItemAnimator} will skip animating the View if its location on the
+         * screen didn't change and your animator should handle this case as well and avoid creating
+         * unnecessary animations.
+         * <p>
+         * When an item is updated, ItemAnimator has a chance to ask RecyclerView to keep the
+         * previous presentation of the item as-is and supply a new ViewHolder for the updated
+         * presentation (see: {@link #canReuseUpdatedViewHolder(ViewHolder)}.
+         * This is useful if you don't know the contents of the Item and would like
+         * to cross-fade the old and the new one ({@link DefaultItemAnimator} uses this technique).
+         * <p>
+         * When you are writing a custom item animator for your layout, it might be more performant
+         * and elegant to re-use the same ViewHolder and animate the content changes manually.
+         * <p>
+         * When {@link Adapter#notifyItemChanged(int)} is called, the Item's view type may change.
+         * If the Item's view type has changed or ItemAnimator returned <code>false</code> for
+         * this ViewHolder when {@link #canReuseUpdatedViewHolder(ViewHolder)} was called, the
+         * <code>oldHolder</code> and <code>newHolder</code> will be different ViewHolder instances
+         * which represent the same Item. In that case, only the new ViewHolder is visible
+         * to the LayoutManager but RecyclerView keeps old ViewHolder attached for animations.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} for each distinct
+         * ViewHolder when their animation is complete
+         * (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it decides not to
+         * animate the view).
+         * <p>
+         *  If oldHolder and newHolder are the same instance, you should call
+         * {@link #dispatchAnimationFinished(ViewHolder)} <b>only once</b>.
+         *
+         * @param oldHolder     The ViewHolder before the layout is started, might be the same
+         *                      instance with newHolder.
+         * @param newHolder     The ViewHolder after the layout is finished, might be the same
+         *                      instance with oldHolder.
+         * @param preLayoutInfo  The information that was returned from
+         *                       {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * @param postLayoutInfo The information that was returned from {@link
+         *                       #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animateChange(@NonNull ViewHolder oldHolder,
+                @NonNull ViewHolder newHolder,
+                @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+        @AdapterChanges static int buildAdapterChangeFlagsForAnimations(ViewHolder viewHolder) {
+            int flags = viewHolder.mFlags & (FLAG_INVALIDATED | FLAG_REMOVED | FLAG_CHANGED);
+            if (viewHolder.isInvalid()) {
+                return FLAG_INVALIDATED;
+            }
+            if ((flags & FLAG_INVALIDATED) == 0) {
+                final int oldPos = viewHolder.getOldPosition();
+                final int pos = viewHolder.getAdapterPosition();
+                if (oldPos != NO_POSITION && pos != NO_POSITION && oldPos != pos){
+                    flags |= FLAG_MOVED;
+                }
+            }
+            return flags;
+        }
+
+        /**
          * Called when there are pending animations waiting to be started. This state
-         * is governed by the return values from {@link #animateAdd(ViewHolder) animateAdd()},
-         * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()}, and
-         * {@link #animateRemove(ViewHolder) animateRemove()}, which inform the
-         * RecyclerView that the ItemAnimator wants to be called later to start the
-         * associated animations. runPendingAnimations() will be scheduled to be run
-         * on the next frame.
+         * is governed by the return values from
+         * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateAppearance()},
+         * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateChange()}
+         * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animatePersistence()}, and
+         * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateDisappearance()}, which inform the RecyclerView that the ItemAnimator wants to be
+         * called later to start the associated animations. runPendingAnimations() will be scheduled
+         * to be run on the next frame.
          */
         abstract public void runPendingAnimations();
 
         /**
-         * Called when an item is removed from the RecyclerView. Implementors can choose
-         * whether and how to animate that change, but must always call
-         * {@link #dispatchRemoveFinished(ViewHolder)} when done, either
-         * immediately (if no animation will occur) or after the animation actually finishes.
-         * The return value indicates whether an animation has been set up and whether the
-         * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
-         * next opportunity. This mechanism allows ItemAnimator to set up individual animations
-         * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
-         * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
-         * {@link #animateRemove(ViewHolder) animateRemove()}, and
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
-         * then start the animations together in the later call to {@link #runPendingAnimations()}.
-         *
-         * <p>This method may also be called for disappearing items which continue to exist in the
-         * RecyclerView, but for which the system does not have enough information to animate
-         * them out of view. In that case, the default animation for removing items is run
-         * on those items as well.</p>
-         *
-         * @param holder The item that is being removed.
-         * @return true if a later call to {@link #runPendingAnimations()} is requested,
-         * false otherwise.
-         */
-        abstract public boolean animateRemove(ViewHolder holder);
-
-        /**
-         * Called when an item is added to the RecyclerView. Implementors can choose
-         * whether and how to animate that change, but must always call
-         * {@link #dispatchAddFinished(ViewHolder)} when done, either
-         * immediately (if no animation will occur) or after the animation actually finishes.
-         * The return value indicates whether an animation has been set up and whether the
-         * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
-         * next opportunity. This mechanism allows ItemAnimator to set up individual animations
-         * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
-         * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
-         * {@link #animateRemove(ViewHolder) animateRemove()}, and
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
-         * then start the animations together in the later call to {@link #runPendingAnimations()}.
-         *
-         * <p>This method may also be called for appearing items which were already in the
-         * RecyclerView, but for which the system does not have enough information to animate
-         * them into view. In that case, the default animation for adding items is run
-         * on those items as well.</p>
-         *
-         * @param holder The item that is being added.
-         * @return true if a later call to {@link #runPendingAnimations()} is requested,
-         * false otherwise.
-         */
-        abstract public boolean animateAdd(ViewHolder holder);
-
-        /**
-         * Called when an item is moved in the RecyclerView. Implementors can choose
-         * whether and how to animate that change, but must always call
-         * {@link #dispatchMoveFinished(ViewHolder)} when done, either
-         * immediately (if no animation will occur) or after the animation actually finishes.
-         * The return value indicates whether an animation has been set up and whether the
-         * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
-         * next opportunity. This mechanism allows ItemAnimator to set up individual animations
-         * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
-         * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
-         * {@link #animateRemove(ViewHolder) animateRemove()}, and
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
-         * then start the animations together in the later call to {@link #runPendingAnimations()}.
-         *
-         * @param holder The item that is being moved.
-         * @return true if a later call to {@link #runPendingAnimations()} is requested,
-         * false otherwise.
-         */
-        abstract public boolean animateMove(ViewHolder holder, int fromX, int fromY,
-                int toX, int toY);
-
-        /**
-         * Called when an item is changed in the RecyclerView, as indicated by a call to
-         * {@link Adapter#notifyItemChanged(int)} or
-         * {@link Adapter#notifyItemRangeChanged(int, int)}.
-         * <p>
-         * Implementers can choose whether and how to animate changes, but must always call
-         * {@link #dispatchChangeFinished(ViewHolder, boolean)} for each non-null ViewHolder,
-         * either immediately (if no animation will occur) or after the animation actually finishes.
-         * The return value indicates whether an animation has been set up and whether the
-         * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
-         * next opportunity. This mechanism allows ItemAnimator to set up individual animations
-         * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
-         * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
-         * {@link #animateRemove(ViewHolder) animateRemove()}, and
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
-         * then start the animations together in the later call to {@link #runPendingAnimations()}.
-         *
-         * @param oldHolder The original item that changed.
-         * @param newHolder The new item that was created with the changed content. Might be null
-         * @param fromLeft  Left of the old view holder
-         * @param fromTop   Top of the old view holder
-         * @param toLeft    Left of the new view holder
-         * @param toTop     Top of the new view holder
-         * @return true if a later call to {@link #runPendingAnimations()} is requested,
-         * false otherwise.
-         */
-        abstract public boolean animateChange(ViewHolder oldHolder,
-                ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop);
-
-
-        /**
-         * Method to be called by subclasses when a remove animation is done.
-         *
-         * @param item The item which has been removed
-         */
-        public final void dispatchRemoveFinished(ViewHolder item) {
-            onRemoveFinished(item);
-            if (mListener != null) {
-                mListener.onRemoveFinished(item);
-            }
-        }
-
-        /**
-         * Method to be called by subclasses when a move animation is done.
-         *
-         * @param item The item which has been moved
-         */
-        public final void dispatchMoveFinished(ViewHolder item) {
-            onMoveFinished(item);
-            if (mListener != null) {
-                mListener.onMoveFinished(item);
-            }
-        }
-
-        /**
-         * Method to be called by subclasses when an add animation is done.
-         *
-         * @param item The item which has been added
-         */
-        public final void dispatchAddFinished(ViewHolder item) {
-            onAddFinished(item);
-            if (mListener != null) {
-                mListener.onAddFinished(item);
-            }
-        }
-
-        /**
-         * Method to be called by subclasses when a change animation is done.
-         *
-         * @see #animateChange(ViewHolder, ViewHolder, int, int, int, int)
-         * @param item The item which has been changed (this method must be called for
-         * each non-null ViewHolder passed into
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
-         * @param oldItem true if this is the old item that was changed, false if
-         * it is the new item that replaced the old item.
-         */
-        public final void dispatchChangeFinished(ViewHolder item, boolean oldItem) {
-            onChangeFinished(item, oldItem);
-            if (mListener != null) {
-                mListener.onChangeFinished(item);
-            }
-        }
-
-        /**
-         * Method to be called by subclasses when a remove animation is being started.
-         *
-         * @param item The item being removed
-         */
-        public final void dispatchRemoveStarting(ViewHolder item) {
-            onRemoveStarting(item);
-        }
-
-        /**
-         * Method to be called by subclasses when a move animation is being started.
-         *
-         * @param item The item being moved
-         */
-        public final void dispatchMoveStarting(ViewHolder item) {
-            onMoveStarting(item);
-        }
-
-        /**
-         * Method to be called by subclasses when an add animation is being started.
-         *
-         * @param item The item being added
-         */
-        public final void dispatchAddStarting(ViewHolder item) {
-            onAddStarting(item);
-        }
-
-        /**
-         * Method to be called by subclasses when a change animation is being started.
-         *
-         * @param item The item which has been changed (this method must be called for
-         * each non-null ViewHolder passed into
-         * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
-         * @param oldItem true if this is the old item that was changed, false if
-         * it is the new item that replaced the old item.
-         */
-        public final void dispatchChangeStarting(ViewHolder item, boolean oldItem) {
-            onChangeStarting(item, oldItem);
-        }
-
-        /**
          * Method called when an animation on a view should be ended immediately.
          * This could happen when other events, like scrolling, occur, so that
          * animating views can be quickly put into their proper end locations.
          * Implementations should ensure that any animations running on the item
          * are canceled and affected properties are set to their end values.
-         * Also, appropriate dispatch methods (e.g., {@link #dispatchAddFinished(ViewHolder)}
-         * should be called since the animations are effectively done when this
-         * method is called.
+         * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished
+         * animation since the animations are effectively done when this method is called.
          *
          * @param item The item for which an animation should be stopped.
          */
@@ -10045,9 +9982,8 @@
          * animating views can be quickly put into their proper end locations.
          * Implementations should ensure that any animations running on any items
          * are canceled and affected properties are set to their end values.
-         * Also, appropriate dispatch methods (e.g., {@link #dispatchAddFinished(ViewHolder)}
-         * should be called since the animations are effectively done when this
-         * method is called.
+         * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished
+         * animation since the animations are effectively done when this method is called.
          */
         abstract public void endAnimations();
 
@@ -10061,6 +9997,82 @@
         abstract public boolean isRunning();
 
         /**
+         * Method to be called by subclasses when an animation is finished.
+         * <p>
+         * For each call RecyclerView makes to
+         * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateAppearance()},
+         * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animatePersistence()}, or
+         * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateDisappearance()}, there
+         * should
+         * be a matching {@link #dispatchAnimationFinished(ViewHolder)} call by the subclass.
+         * <p>
+         * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateChange()}, sublcass should call this method for both the <code>oldHolder</code>
+         * and <code>newHolder</code>  (if they are not the same instance).
+         *
+         * @param viewHolder The ViewHolder whose animation is finished.
+         * @see #onAnimationFinished(ViewHolder)
+         */
+        public final void dispatchAnimationFinished(ViewHolder viewHolder) {
+            onAnimationFinished(viewHolder);
+            if (mListener != null) {
+                mListener.onAnimationFinished(viewHolder);
+            }
+        }
+
+        /**
+         * Called after {@link #dispatchAnimationFinished(ViewHolder)} is called by the
+         * ItemAniamtor.
+         *
+         * @param viewHolder The ViewHolder whose animation is finished. There might still be other
+         *                   animations running on this ViewHolder.
+         * @see #dispatchAnimationFinished(ViewHolder)
+         */
+        public void onAnimationFinished(ViewHolder viewHolder) {
+        }
+
+        /**
+         * Method to be called by subclasses when an animation is started.
+         * <p>
+         * For each call RecyclerView makes to
+         * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateAppearance()},
+         * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animatePersistence()}, or
+         * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateDisappearance()}, there should be a matching
+         * {@link #dispatchAnimationStarted(ViewHolder)} call by the subclass.
+         * <p>
+         * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateChange()}, sublcass should call this method for both the <code>oldHolder</code>
+         * and <code>newHolder</code> (if they are not the same instance).
+         * <p>
+         * If your ItemAnimator decides not to animate a ViewHolder, it should call
+         * {@link #dispatchAnimationFinished(ViewHolder)} <b>without</b> calling
+         * {@link #dispatchAnimationStarted(ViewHolder)}.
+         *
+         * @param viewHolder The ViewHolder whose animation is starting.
+         * @see #onAnimationStarted(ViewHolder)
+         */
+        public final void dispatchAnimationStarted(ViewHolder viewHolder) {
+            onAnimationStarted(viewHolder);
+        }
+
+        /**
+         * Called when a new animation is started on the given ViewHolder.
+         *
+         * @param viewHolder The ViewHolder which started animating. Note that the ViewHolder
+         *                   might already be animating and this might be another animation.
+         * @see #dispatchAnimationStarted(ViewHolder)
+         */
+        public void onAnimationStarted(ViewHolder viewHolder) {
+
+        }
+
+        /**
          * Like {@link #isRunning()}, this method returns whether there are any item
          * animations currently running. Addtionally, the listener passed in will be called
          * when there are no item animations running, either immediately (before the method
@@ -10089,15 +10101,23 @@
         }
 
         /**
-         * The interface to be implemented by listeners to animation events from this
-         * ItemAnimator. This is used internally and is not intended for developers to
-         * create directly.
+         * When an item is changed, ItemAnimator can decide whether it wants to re-use
+         * the same ViewHolder for animations or RecyclerView should create a copy of the
+         * item and ItemAnimator will use both to run the animation (e.g. cross-fade).
+         * <p>
+         * Note that this method will only be called if the {@link ViewHolder} still has the same
+         * type ({@link Adapter#getItemViewType(int)}). Otherwise, ItemAnimator will always receive
+         * both {@link ViewHolder}s in the
+         * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)} method.
+         *
+         * @param viewHolder The ViewHolder which represents the changed item's old content.
+         *
+         * @return True if RecyclerView should just rebind to the same ViewHolder or false if
+         *         RecyclerView should create a new ViewHolder and pass this ViewHolder to the
+         *         ItemAnimator to animate. Default implementation returns <code>true</code>.
          */
-        interface ItemAnimatorListener {
-            void onRemoveFinished(ViewHolder item);
-            void onAddFinished(ViewHolder item);
-            void onMoveFinished(ViewHolder item);
-            void onChangeFinished(ViewHolder item);
+        public boolean canReuseUpdatedViewHolder(ViewHolder viewHolder) {
+            return true;
         }
 
         /**
@@ -10113,6 +10133,28 @@
         }
 
         /**
+         * Returns a new {@link ItemHolderInfo} which will be used to store information about the
+         * ViewHolder. This information will later be passed into <code>animate**</code> methods.
+         * <p>
+         * You can override this method if you want to extend {@link ItemHolderInfo} and provide
+         * your own instances.
+         *
+         * @return A new {@link ItemHolderInfo}.
+         */
+        public ItemHolderInfo obtainHolderInfo() {
+            return new ItemHolderInfo();
+        }
+
+        /**
+         * The interface to be implemented by listeners to animation events from this
+         * ItemAnimator. This is used internally and is not intended for developers to
+         * create directly.
+         */
+        interface ItemAnimatorListener {
+            void onAnimationFinished(ViewHolder item);
+        }
+
+        /**
          * This interface is used to inform listeners when all pending or running animations
          * in an ItemAnimator are finished. This can be used, for example, to delay an action
          * in a data set until currently-running animations are complete.
@@ -10124,105 +10166,79 @@
         }
 
         /**
-         * Called when a remove animation is being started on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
+         * A simple data structure that holds information about an item's bounds.
+         * This information is used in calculating item animations. Default implementation of
+         * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)} and
+         * {@link #recordPostLayoutInformation(RecyclerView.State, ViewHolder)} returns this data
+         * structure. You can extend this class if you would like to keep more information about
+         * the Views.
+         * <p>
+         * If you want to provide your own implementation butstill use `super` methods to record
+         * basic information, you can override {@link #obtainHolderInfo()} to provide your own
+         * instances.
          */
-        public void onRemoveStarting(ViewHolder item) {}
+        public static class ItemHolderInfo {
 
-        /**
-         * Called when a remove animation has ended on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
-         */
-        public void onRemoveFinished(ViewHolder item) {}
+            /**
+             * The left edge of the View (excluding decorations)
+             */
+            public int left;
 
-        /**
-         * Called when an add animation is being started on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
-         */
-        public void onAddStarting(ViewHolder item) {}
+            /**
+             * The top edge of the View (excluding decorations)
+             */
+            public int top;
 
-        /**
-         * Called when an add animation has ended on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
-         */
-        public void onAddFinished(ViewHolder item) {}
+            /**
+             * The right edge of the View (excluding decorations)
+             */
+            public int right;
 
-        /**
-         * Called when a move animation is being started on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
-         */
-        public void onMoveStarting(ViewHolder item) {}
+            /**
+             * The bottom edge of the View (excluding decorations)
+             */
+            public int bottom;
 
-        /**
-         * Called when a move animation has ended on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
-         */
-        public void onMoveFinished(ViewHolder item) {}
+            /**
+             * The change flags that were passed to
+             * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)}.
+             */
+            @AdapterChanges
+            public int changeFlags;
 
-        /**
-         * Called when a change animation is being started on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
-         * @param oldItem true if this is the old item that was changed, false if
-         * it is the new item that replaced the old item.
-         */
-        public void onChangeStarting(ViewHolder item, boolean oldItem) {}
+            public ItemHolderInfo() {
+            }
 
-        /**
-         * Called when a change animation has ended on the given ViewHolder.
-         * The default implementation does nothing. Subclasses may wish to override
-         * this method to handle any ViewHolder-specific operations linked to animation
-         * lifecycles.
-         *
-         * @param item The ViewHolder being animated.
-         * @param oldItem true if this is the old item that was changed, false if
-         * it is the new item that replaced the old item.
-         */
-        public void onChangeFinished(ViewHolder item, boolean oldItem) {}
+            /**
+             * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from
+             * the given ViewHolder. Clears all {@link #changeFlags}.
+             *
+             * @param holder The ViewHolder whose bounds should be copied.
+             * @return This {@link ItemHolderInfo}
+             */
+            public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder) {
+                return setFrom(holder, 0);
+            }
 
-    }
-
-    /**
-     * Internal data structure that holds information about an item's bounds.
-     * This information is used in calculating item animations.
-     */
-    private static class ItemHolderInfo {
-        ViewHolder holder;
-        int left, top, right, bottom;
-
-        ItemHolderInfo(ViewHolder holder, int left, int top, int right, int bottom) {
-            this.holder = holder;
-            this.left = left;
-            this.top = top;
-            this.right = right;
-            this.bottom = bottom;
+            /**
+             * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from
+             * the given ViewHolder and sets the {@link #changeFlags} to the given flags parameter.
+             *
+             * @param holder The ViewHolder whose bounds should be copied.
+             * @param flags  The adapter change flags that were passed into
+             *               {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int,
+             *               List)}.
+             * @return This {@link ItemHolderInfo}
+             */
+            public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder,
+                    @AdapterChanges int flags) {
+                final View view = holder.itemView;
+                this.left = view.getLeft();
+                this.top = view.getTop();
+                this.right = view.getRight();
+                this.bottom = view.getBottom();
+                return this;
+            }
         }
     }
 
@@ -10243,7 +10259,7 @@
      * order of two views will not have any effect if their elevation values are different since
      * elevation overrides the result of this callback.
      */
-    public static interface ChildDrawingOrderCallback {
+    public interface ChildDrawingOrderCallback {
         /**
          * Returns the index of the child to draw for this iteration. Override this
          * if you want to change the drawing order of children. By default, it
@@ -10254,6 +10270,6 @@
          *
          * @see RecyclerView#setChildDrawingOrderCallback(RecyclerView.ChildDrawingOrderCallback)
          */
-        public int onGetChildDrawingOrder(int childCount, int i);
+        int onGetChildDrawingOrder(int childCount, int i);
     }
 }
diff --git a/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java b/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
new file mode 100644
index 0000000..1266236
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
@@ -0,0 +1,429 @@
+package android.support.v7.widget;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * A wrapper class for ItemAnimator that records View bounds and decides whether it should run
+ * move, change, add or remove animations. This class also replicates the original ItemAnimator
+ * API.
+ * <p>
+ * It uses {@link ItemHolderInfo} to track the bounds information of the Views. If you would like
+ * to
+ * extend this class, you can override {@link #obtainHolderInfo()} method to provide your own info
+ * class that extends {@link ItemHolderInfo}.
+ */
+abstract public class
+        SimpleItemAnimator extends RecyclerView.ItemAnimator {
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "SimpleItemAnimator";
+
+    boolean mSupportsChangeAnimations = true;
+
+    /**
+     * Returns whether this ItemAnimator supports animations of change events.
+     *
+     * @return true if change animations are supported, false otherwise
+     */
+    @SuppressWarnings("unused")
+    public boolean getSupportsChangeAnimations() {
+        return mSupportsChangeAnimations;
+    }
+
+    /**
+     * Sets whether this ItemAnimator supports animations of item change events.
+     * If you set this property to false, actions on the data set which change the
+     * contents of items will not be animated. What those animations do is left
+     * up to the discretion of the ItemAnimator subclass, in its
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} implementation.
+     * The value of this property is true by default.
+     *
+     * @param supportsChangeAnimations true if change animations are supported by
+     *                                 this ItemAnimator, false otherwise. If the property is false,
+     *                                 the ItemAnimator
+     *                                 will not receive a call to
+     *                                 {@link #animateChange(ViewHolder, ViewHolder, int, int, int,
+     *                                 int)} when changes occur.
+     * @see Adapter#notifyItemChanged(int)
+     * @see Adapter#notifyItemRangeChanged(int, int)
+     */
+    public void setSupportsChangeAnimations(boolean supportsChangeAnimations) {
+        mSupportsChangeAnimations = supportsChangeAnimations;
+    }
+
+    @Override
+    public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
+        return !mSupportsChangeAnimations || viewHolder.isInvalid();
+    }
+
+    @Override
+    public boolean animateDisappearance(@NonNull ViewHolder viewHolder,
+            @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
+        int oldLeft = preLayoutInfo.left;
+        int oldTop = preLayoutInfo.top;
+        View disappearingItemView = viewHolder.itemView;
+        int newLeft = postLayoutInfo == null ? disappearingItemView.getLeft() : postLayoutInfo.left;
+        int newTop = postLayoutInfo == null ? disappearingItemView.getTop() : postLayoutInfo.top;
+        if (!viewHolder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
+            disappearingItemView.layout(newLeft, newTop,
+                    newLeft + disappearingItemView.getWidth(),
+                    newTop + disappearingItemView.getHeight());
+            if (DEBUG) {
+                Log.d(TAG, "DISAPPEARING: " + viewHolder + " with view " + disappearingItemView);
+            }
+            return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop);
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "REMOVED: " + viewHolder + " with view " + disappearingItemView);
+            }
+            return animateRemove(viewHolder);
+        }
+    }
+
+    @Override
+    public boolean animateAppearance(@NonNull ViewHolder viewHolder,
+            @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
+        if (preLayoutInfo != null && (preLayoutInfo.left != postLayoutInfo.left
+                || preLayoutInfo.top != postLayoutInfo.top)) {
+            // slide items in if before/after locations differ
+            if (DEBUG) {
+                Log.d(TAG, "APPEARING: " + viewHolder + " with view " + viewHolder);
+            }
+            return animateMove(viewHolder, preLayoutInfo.left, preLayoutInfo.top,
+                    postLayoutInfo.left, postLayoutInfo.top);
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "ADDED: " + viewHolder + " with view " + viewHolder);
+            }
+            return animateAdd(viewHolder);
+        }
+    }
+
+    @Override
+    public boolean animatePersistence(@NonNull ViewHolder viewHolder,
+            @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+        if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
+            if (DEBUG) {
+                Log.d(TAG, "PERSISTENT: " + viewHolder +
+                        " with view " + viewHolder.itemView);
+            }
+            return animateMove(viewHolder,
+                    preInfo.left, preInfo.top, postInfo.left, postInfo.top);
+        }
+        dispatchMoveFinished(viewHolder);
+        return false;
+    }
+
+    @Override
+    public boolean animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder,
+            @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+        if (DEBUG) {
+            Log.d(TAG, "CHANGED: " + oldHolder + " with view " + oldHolder.itemView);
+        }
+        final int fromLeft = preInfo.left;
+        final int fromTop = preInfo.top;
+        final int toLeft, toTop;
+        if (newHolder.shouldIgnore()) {
+            toLeft = preInfo.left;
+            toTop = preInfo.top;
+        } else {
+            toLeft = postInfo.left;
+            toTop = postInfo.top;
+        }
+        return animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft, toTop);
+    }
+
+    /**
+     * Called when an item is removed from the RecyclerView. Implementors can choose
+     * whether and how to animate that change, but must always call
+     * {@link #dispatchRemoveFinished(ViewHolder)} when done, either
+     * immediately (if no animation will occur) or after the animation actually finishes.
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * <p>This method may also be called for disappearing items which continue to exist in the
+     * RecyclerView, but for which the system does not have enough information to animate
+     * them out of view. In that case, the default animation for removing items is run
+     * on those items as well.</p>
+     *
+     * @param holder The item that is being removed.
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    abstract public boolean animateRemove(ViewHolder holder);
+
+    /**
+     * Called when an item is added to the RecyclerView. Implementors can choose
+     * whether and how to animate that change, but must always call
+     * {@link #dispatchAddFinished(ViewHolder)} when done, either
+     * immediately (if no animation will occur) or after the animation actually finishes.
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * <p>This method may also be called for appearing items which were already in the
+     * RecyclerView, but for which the system does not have enough information to animate
+     * them into view. In that case, the default animation for adding items is run
+     * on those items as well.</p>
+     *
+     * @param holder The item that is being added.
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    abstract public boolean animateAdd(ViewHolder holder);
+
+    /**
+     * Called when an item is moved in the RecyclerView. Implementors can choose
+     * whether and how to animate that change, but must always call
+     * {@link #dispatchMoveFinished(ViewHolder)} when done, either
+     * immediately (if no animation will occur) or after the animation actually finishes.
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * @param holder The item that is being moved.
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    abstract public boolean animateMove(ViewHolder holder, int fromX, int fromY,
+            int toX, int toY);
+
+    /**
+     * Called when an item is changed in the RecyclerView, as indicated by a call to
+     * {@link Adapter#notifyItemChanged(int)} or
+     * {@link Adapter#notifyItemRangeChanged(int, int)}.
+     * <p>
+     * Implementers can choose whether and how to animate changes, but must always call
+     * {@link #dispatchChangeFinished(ViewHolder, boolean)} for each non-null ViewHolder,
+     * either immediately (if no animation will occur) or after the animation actually finishes.
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * @param oldHolder The original item that changed.
+     * @param newHolder The new item that was created with the changed content. Might be null
+     * @param fromLeft  Left of the old view holder
+     * @param fromTop   Top of the old view holder
+     * @param toLeft    Left of the new view holder
+     * @param toTop     Top of the new view holder
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    abstract public boolean animateChange(ViewHolder oldHolder,
+            ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop);
+
+    /**
+     * Method to be called by subclasses when a remove animation is done.
+     *
+     * @param item The item which has been removed
+     * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
+     * ItemHolderInfo)
+     */
+    public final void dispatchRemoveFinished(ViewHolder item) {
+        onRemoveFinished(item);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a move animation is done.
+     *
+     * @param item The item which has been moved
+     * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
+     * ItemHolderInfo)
+     * @see RecyclerView.ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     * @see RecyclerView.ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     */
+    public final void dispatchMoveFinished(ViewHolder item) {
+        onMoveFinished(item);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when an add animation is done.
+     *
+     * @param item The item which has been added
+     */
+    public final void dispatchAddFinished(ViewHolder item) {
+        onAddFinished(item);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a change animation is done.
+     *
+     * @param item    The item which has been changed (this method must be called for
+     *                each non-null ViewHolder passed into
+     *                {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     * @see #animateChange(ViewHolder, ViewHolder, int, int, int, int)
+     */
+    public final void dispatchChangeFinished(ViewHolder item, boolean oldItem) {
+        onChangeFinished(item, oldItem);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a remove animation is being started.
+     *
+     * @param item The item being removed
+     */
+    public final void dispatchRemoveStarting(ViewHolder item) {
+        onRemoveStarting(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a move animation is being started.
+     *
+     * @param item The item being moved
+     */
+    public final void dispatchMoveStarting(ViewHolder item) {
+        onMoveStarting(item);
+    }
+
+    /**
+     * Method to be called by subclasses when an add animation is being started.
+     *
+     * @param item The item being added
+     */
+    public final void dispatchAddStarting(ViewHolder item) {
+        onAddStarting(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a change animation is being started.
+     *
+     * @param item    The item which has been changed (this method must be called for
+     *                each non-null ViewHolder passed into
+     *                {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     */
+    public final void dispatchChangeStarting(ViewHolder item, boolean oldItem) {
+        onChangeStarting(item, oldItem);
+    }
+
+    /**
+     * Called when a remove animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onRemoveStarting(ViewHolder item) {
+    }
+
+    /**
+     * Called when a remove animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    public void onRemoveFinished(ViewHolder item) {
+    }
+
+    /**
+     * Called when an add animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onAddStarting(ViewHolder item) {
+    }
+
+    /**
+     * Called when an add animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    public void onAddFinished(ViewHolder item) {
+    }
+
+    /**
+     * Called when a move animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onMoveStarting(ViewHolder item) {
+    }
+
+    /**
+     * Called when a move animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    public void onMoveFinished(ViewHolder item) {
+    }
+
+    /**
+     * Called when a change animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item    The ViewHolder being animated.
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onChangeStarting(ViewHolder item, boolean oldItem) {
+    }
+
+    /**
+     * Called when a change animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item    The ViewHolder being animated.
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     */
+    public void onChangeFinished(ViewHolder item, boolean oldItem) {
+    }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
index 322fe34..071bb4e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -1040,7 +1040,7 @@
         final int mode = View.MeasureSpec.getMode(spec);
         if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
             return View.MeasureSpec.makeMeasureSpec(
-                    View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
+                    Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode);
         }
         return spec;
     }
@@ -2676,7 +2676,10 @@
         }
     }
 
-    static class SavedState implements Parcelable {
+    /**
+     * @hide
+     */
+    public static class SavedState implements Parcelable {
 
         int mAnchorPosition;
         int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
diff --git a/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java b/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
new file mode 100644
index 0000000..0af8dfb
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.util.LongSparseArray;
+import android.support.v4.util.Pools;
+
+import static android.support.v7.widget.RecyclerView.ViewHolder;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
+/**
+ * This class abstracts all tracking for Views to run animations
+ *
+ * @hide
+ */
+class ViewInfoStore {
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * View data records for pre-layout
+     */
+    @VisibleForTesting
+    final ArrayMap<ViewHolder, InfoRecord> mLayoutHolderMap = new ArrayMap<>();
+
+    @VisibleForTesting
+    final LongSparseArray<ViewHolder> mOldChangedHolders = new LongSparseArray<>();
+
+    /**
+     * Clears the state and all existing tracking data
+     */
+    void clear() {
+        mLayoutHolderMap.clear();
+        mOldChangedHolders.clear();
+    }
+
+    /**
+     * Adds the item information to the prelayout tracking
+     * @param holder The ViewHolder whose information is being saved
+     * @param info The information to save
+     */
+    void addToPreLayout(ViewHolder holder, ItemHolderInfo info) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.preInfo = info;
+        record.flags |= FLAG_PRE;
+    }
+
+    /**
+     * Finds the ItemHolderInfo for the given ViewHolder in preLayout list and removes it.
+     * @param vh The ViewHolder whose information is being queried
+     * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
+     */
+    @Nullable
+    ItemHolderInfo popFromPreLayout(ViewHolder vh) {
+        int index = mLayoutHolderMap.indexOfKey(vh);
+        if (index < 0) {
+            return null;
+        }
+        final InfoRecord record = mLayoutHolderMap.valueAt(index);
+        if (record != null && (record.flags & FLAG_PRE) != 0) {
+            record.flags &= ~FLAG_PRE;
+            final ItemHolderInfo info = record.preInfo;
+            if (record.flags == 0) {
+                mLayoutHolderMap.removeAt(index);
+                InfoRecord.recycle(record);
+            }
+            return info;
+        }
+        return null;
+    }
+
+    /**
+     * Adds the given ViewHolder to the oldChangeHolders list
+     * @param key The key to identify the ViewHolder.
+     * @param holder The ViewHolder to store
+     */
+    void addToOldChangeHolders(long key, ViewHolder holder) {
+        mOldChangedHolders.put(key, holder);
+    }
+
+    /**
+     * Adds the given ViewHolder to the appeared in pre layout list. These are Views added by the
+     * LayoutManager during a pre-layout pass. We distinguish them from other views that were
+     * already in the pre-layout so that ItemAnimator can choose to run a different animation for
+     * them.
+     *
+     * @param holder The ViewHolder to store
+     * @param info The information to save
+     */
+    void addToAppearedInPreLayoutHolders(ViewHolder holder, ItemHolderInfo info) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.flags |= FLAG_APPEAR;
+        record.preInfo = info;
+    }
+
+    /**
+     * Checks whether the given ViewHolder is in preLayout list
+     * @param viewHolder The ViewHolder to query
+     *
+     * @return True if the ViewHolder is present in preLayout, false otherwise
+     */
+    boolean isInPreLayout(ViewHolder viewHolder) {
+        final InfoRecord record = mLayoutHolderMap.get(viewHolder);
+        return record != null && (record.flags & FLAG_PRE) != 0;
+    }
+
+    /**
+     * Queries the oldChangeHolder list for the given key. If they are not tracked, simply returns
+     * null.
+     * @param key The key to be used to find the ViewHolder.
+     *
+     * @return A ViewHolder if exists or null if it does not exist.
+     */
+    ViewHolder getFromOldChangeHolders(long key) {
+        return mOldChangedHolders.get(key);
+    }
+
+    /**
+     * Adds the item information to the post layout list
+     * @param holder The ViewHolder whose information is being saved
+     * @param info The information to save
+     */
+    void addToPostLayout(ViewHolder holder, ItemHolderInfo info) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.postInfo = info;
+        record.flags |= FLAG_POST;
+    }
+
+    /**
+     * A ViewHolder might be added by the LayoutManager just to animate its disappearance.
+     * This list holds such items so that we can animate / recycle these ViewHolders properly.
+     *
+     * @param holder The ViewHolder which disappeared during a layout.
+     */
+    void addToDisappearedInLayout(ViewHolder holder) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.flags |= FLAG_DISAPPEARED;
+    }
+
+    /**
+     * Removes a ViewHolder from disappearing list.
+     * @param holder The ViewHolder to be removed from the disappearing list.
+     */
+    void removeFromDisappearedInLayout(ViewHolder holder) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            return;
+        }
+        record.flags &= ~FLAG_DISAPPEARED;
+    }
+
+    void process(ProcessCallback callback) {
+        for (int index = mLayoutHolderMap.size() - 1; index >= 0; index --) {
+            final ViewHolder viewHolder = mLayoutHolderMap.keyAt(index);
+            final InfoRecord record = mLayoutHolderMap.removeAt(index);
+            if ((record.flags & FLAG_APPEAR_AND_DISAPPEAR) == FLAG_APPEAR_AND_DISAPPEAR) {
+                // Appeared then disappeared. Not useful for animations.
+                callback.unused(viewHolder);
+            } else if ((record.flags & FLAG_DISAPPEARED) != 0) {
+                // Set as "disappeared" by the LayoutManager (addDisappearingView)
+                callback.processDisappeared(viewHolder, record.preInfo, record.postInfo);
+            } else if ((record.flags & FLAG_APPEAR_PRE_AND_POST) == FLAG_APPEAR_PRE_AND_POST) {
+                // Appeared in the layout but not in the adapter (e.g. entered the viewport)
+                callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
+            } else if ((record.flags & FLAG_PRE_AND_POST) == FLAG_PRE_AND_POST) {
+                // Persistent in both passes. Animate persistence
+                callback.processPersistent(viewHolder, record.preInfo, record.postInfo);
+            } else if ((record.flags & FLAG_PRE) != 0) {
+                // Was in pre-layout, never been added to post layout
+                callback.processDisappeared(viewHolder, record.preInfo, null);
+            } else if ((record.flags & FLAG_POST) != 0) {
+                // Was not in pre-layout, been added to post layout
+                callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
+            } else if ((record.flags & FLAG_APPEAR) != 0) {
+                // Scrap view. RecyclerView will handle removing/recycling this.
+            } else if (DEBUG) {
+                throw new IllegalStateException("record without any reasonable flag combination:/");
+            }
+            InfoRecord.recycle(record);
+        }
+    }
+
+    /**
+     * Removes the ViewHolder from all list
+     * @param holder The ViewHolder which we should stop tracking
+     */
+    void removeViewHolder(ViewHolder holder) {
+        for (int i = mOldChangedHolders.size() - 1; i >= 0; i--) {
+            if (holder == mOldChangedHolders.valueAt(i)) {
+                mOldChangedHolders.removeAt(i);
+                break;
+            }
+        }
+        final InfoRecord info = mLayoutHolderMap.remove(holder);
+        if (info != null) {
+            InfoRecord.recycle(info);
+        }
+    }
+
+    void onDetach() {
+        InfoRecord.drainCache();
+    }
+
+    interface ProcessCallback {
+        void processDisappeared(ViewHolder viewHolder, ItemHolderInfo preInfo,
+                @Nullable ItemHolderInfo postInfo);
+        void processAppeared(ViewHolder viewHolder, @Nullable ItemHolderInfo preInfo,
+                ItemHolderInfo postInfo);
+        void processPersistent(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
+                @NonNull ItemHolderInfo postInfo);
+        void unused(ViewHolder holder);
+    }
+
+    static class InfoRecord {
+        // disappearing list
+        static final int FLAG_DISAPPEARED = 1;
+        // appear in pre layout list
+        static final int FLAG_APPEAR = 1 << 1;
+        // pre layout, this is necessary to distinguish null item info
+        static final int FLAG_PRE = 1 << 2;
+        // post layout, this is necessary to distinguish null item info
+        static final int FLAG_POST = 1 << 3;
+        static final int FLAG_APPEAR_AND_DISAPPEAR = FLAG_APPEAR | FLAG_DISAPPEARED;
+        static final int FLAG_PRE_AND_POST = FLAG_PRE | FLAG_POST;
+        static final int FLAG_APPEAR_PRE_AND_POST = FLAG_APPEAR | FLAG_PRE | FLAG_POST;
+        int flags;
+        @Nullable ItemHolderInfo preInfo;
+        @Nullable ItemHolderInfo postInfo;
+        static Pools.Pool<InfoRecord> sPool = new Pools.SimplePool<>(20);
+
+        private InfoRecord() {
+        }
+
+        static InfoRecord obtain() {
+            InfoRecord record = sPool.acquire();
+            return record == null ? new InfoRecord() : record;
+        }
+
+        static void recycle(InfoRecord record) {
+            record.flags = 0;
+            record.preInfo = null;
+            record.postInfo = null;
+            sPool.release(record);
+        }
+
+        static void drainCache() {
+            //noinspection StatementWithEmptyBody
+            while (sPool.acquire() != null);
+        }
+    }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
index 0c22d1c..72d3e8c 100644
--- a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
@@ -873,7 +873,6 @@
                     anim.cancel();
                 }
                 mRecoverAnimations.remove(i);
-                anim.mViewHolder.setIsRecyclable(true);
                 return anim.mAnimationType;
             }
         }
@@ -1902,7 +1901,6 @@
                 final RecoverAnimation anim = recoverAnimationList.get(i);
                 if (anim.mEnded && !anim.mIsPendingCleanup) {
                     recoverAnimationList.remove(i);
-                    anim.mViewHolder.setIsRecyclable(true);
                 } else if (!anim.mEnded) {
                     hasRunningAnimation = true;
                 }
@@ -2314,6 +2312,9 @@
 
         @Override
         public void onAnimationEnd(ValueAnimatorCompat animation) {
+            if (!mEnded) {
+                mViewHolder.setIsRecyclable(true);
+            }
             mEnded = true;
         }
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java b/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
index e9147a0..f985898 100644
--- a/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
@@ -16,22 +16,13 @@
 
 package android.support.v7.util;
 
-import android.support.test.runner.AndroidJUnit4;
+import android.support.annotation.UiThread;
 import android.util.SparseBooleanArray;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-@RunWith(AndroidJUnit4.class)
-public class AsyncListUtilTest {
+public class AsyncListUtilTest extends BaseThreadedTest {
 
     private static final int TILE_SIZE = 10;
 
@@ -40,34 +31,37 @@
 
     AsyncListUtil<String> mAsyncListUtil;
 
-
-    @Before
+    @Override
     public void setUp() throws Exception {
         mDataCallback = new TestDataCallback();
         mViewCallback = new TestViewCallback();
 
         mDataCallback.expectTiles(0, 10, 20);
-        mAsyncListUtil = new AsyncListUtil<String>(String.class, TILE_SIZE, mDataCallback,
-                mViewCallback);
+        super.setUp();
         mDataCallback.waitForTiles("initial load");
     }
 
-    @After
+    @Override
+    @UiThread
+    protected void setUpUi() {
+        mAsyncListUtil = new AsyncListUtil<String>(
+                String.class, TILE_SIZE, mDataCallback, mViewCallback);
+    }
+
+    @Override
     public void tearDown() throws Exception {
         /// Wait a little extra to catch spurious messages.
         new CountDownLatch(1).await(500, TimeUnit.MILLISECONDS);
     }
 
-    @Test
-    public void testWithNoPreload() throws InterruptedException {
+    public void testWithNoPreload() throws Throwable {
         scrollAndExpectTiles(10, "scroll to 10", 30);
         scrollAndExpectTiles(25, "scroll to 25", 40);
         scrollAndExpectTiles(45, "scroll to 45", 50, 60);
         scrollAndExpectTiles(70, "scroll to 70", 70, 80, 90);
     }
 
-    @Test
-    public void testWithPreload() throws InterruptedException {
+    public void testWithPreload() throws Throwable {
         mViewCallback.mStartPreload = 5;
         mViewCallback.mEndPreload = 15;
         scrollAndExpectTiles(50, "scroll down a lot", 40, 50, 60, 70, 80);
@@ -78,8 +72,7 @@
         scrollAndExpectTiles(40, "scroll up a little, no new tiles loaded");
     }
 
-    @Test
-    public void testTileCaching() throws InterruptedException {
+    public void testTileCaching() throws Throwable {
         scrollAndExpectTiles(25, "next screen", 30, 40);
 
         scrollAndExpectTiles(0, "back at top, no new page loads");
@@ -90,35 +83,34 @@
         scrollAndExpectTiles(0, "scroll back to top, all pages should reload", 0, 10, 20);
     }
 
-    @Test
-    public void testDataRefresh() throws InterruptedException {
+    public void testDataRefresh() throws Throwable {
         mViewCallback.expectDataSetChanged(40);
         mDataCallback.expectTiles(0, 10, 20);
-        mAsyncListUtil.refresh();
+        refreshOnUiThread();
         mViewCallback.waitForDataSetChanged("increasing item count");
         mDataCallback.waitForTiles("increasing item count");
 
         mViewCallback.expectDataSetChanged(15);
         mDataCallback.expectTiles(0, 10);
-        mAsyncListUtil.refresh();
+        refreshOnUiThread();
         mViewCallback.waitForDataSetChanged("decreasing item count");
         mDataCallback.waitForTiles("decreasing item count");
     }
 
-    @Test
-    public void testItemChanged() throws InterruptedException {
+    public void testItemChanged() throws Throwable {
         final int position = 30;
         final int count = 20;
 
-        assertEquals("no new items should be loaded", 0, getLoadedItemCount(position, count));
+        assertLoadedItemsOnUiThread("no new items should be loaded", 0, position, count);
 
         mViewCallback.expectItemRangeChanged(position, count);
         scrollAndExpectTiles(20, "scrolling to missing items", 30, 40);
         mViewCallback.waitForItems();
 
-        assertEquals("all new items should be loaded", count, getLoadedItemCount(position, count));
+        assertLoadedItemsOnUiThread("all new items should be loaded", count, position, count);
     }
 
+    @UiThread
     private int getLoadedItemCount(int startPosition, int itemCount) {
         int loaded = 0;
         for (int i = 0; i < itemCount; i++) {
@@ -130,9 +122,9 @@
     }
 
     private void scrollAndExpectTiles(int position, String context, int... positions)
-            throws InterruptedException {
+            throws Throwable {
         mDataCallback.expectTiles(positions);
-        mViewCallback.scrollTo(position);
+        scrollOnUiThread(position);
         mDataCallback.waitForTiles(context);
     }
 
@@ -141,6 +133,36 @@
         assertTrue("timed out waiting for " + context, latch.await(1, TimeUnit.SECONDS));
     }
 
+    private void refreshOnUiThread() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAsyncListUtil.refresh();
+            }
+        });
+    }
+
+    private void assertLoadedItemsOnUiThread(final String message,
+                                             final int expectedCount,
+                                             final int position,
+                                             final int count) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(message, expectedCount, getLoadedItemCount(position, count));
+            }
+        });
+    }
+
+    private void scrollOnUiThread(final int position) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mViewCallback.scrollTo(position);
+            }
+        });
+    }
+
     private class TestDataCallback extends AsyncListUtil.DataCallback<String> {
         private int mCacheSize = 10;
 
@@ -205,6 +227,7 @@
         }
 
         @Override
+        @UiThread
         public void onDataRefresh() {
             if (mDataRefreshLatch == null) {
                 return;
@@ -239,12 +262,14 @@
             waitForLatch("onItemChanged", mItemsChangedLatch.mLatch);
         }
 
+        @UiThread
         public void scrollTo(int position) {
             mLastVisibleItem += position - mFirstVisibleItem;
             mFirstVisibleItem = position;
             mAsyncListUtil.onRangeChanged();
         }
 
+        @UiThread
         private void updateViewport() {
             int itemCount = mAsyncListUtil.getItemCount();
             if (mLastVisibleItem < itemCount) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/BaseThreadedTest.java b/v7/recyclerview/tests/src/android/support/v7/util/BaseThreadedTest.java
new file mode 100644
index 0000000..73df9a7
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/util/BaseThreadedTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.util;
+
+import android.support.annotation.UiThread;
+import android.support.v7.widget.TestActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+abstract public class BaseThreadedTest extends ActivityInstrumentationTestCase2<TestActivity> {
+    public BaseThreadedTest() {
+        super(TestActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception{
+        try {
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setUpUi();
+                }
+            });
+        } catch (Throwable throwable) {
+            fail(throwable.getMessage());
+        }
+    }
+
+    @UiThread
+    protected abstract void setUpUi();
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java b/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java
index daa2ffc..472374d 100644
--- a/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java
@@ -19,27 +19,23 @@
 import static org.hamcrest.MatcherAssert.*;
 import static org.hamcrest.CoreMatchers.*;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
+import android.support.annotation.UiThread;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
-@RunWith(AndroidJUnit4.class)
-public class ThreadUtilTest {
+public class ThreadUtilTest extends BaseThreadedTest {
     Map<String, LockedObject> results = new HashMap<>();
 
     ThreadUtil.MainThreadCallback<Integer> mMainThreadProxy;
     ThreadUtil.BackgroundCallback<Integer> mBackgroundProxy;
 
-    @Before
-    public void setup() {
+    @Override
+    @UiThread
+    public void setUpUi() {
         ThreadUtil<Integer> threadUtil = new MessageThreadUtil<>();
 
         mMainThreadProxy = threadUtil.getMainThreadProxy(
@@ -93,15 +89,15 @@
                 });
     }
 
-    @Test
     public void testUpdateItemCount() throws InterruptedException {
         initWait("updateItemCount");
+        // In this test and below the calls to mMainThreadProxy are not really made from the UI
+        // thread. That's OK since the message queue inside mMainThreadProxy is synchronized.
         mMainThreadProxy.updateItemCount(7, 9);
         Object[] data = waitFor("updateItemCount");
         assertThat(data, is(new Object[]{7, 9}));
     }
 
-    @Test
     public void testAddTile() throws InterruptedException {
         initWait("addTile");
         TileList.Tile<Integer> tile = new TileList.Tile<Integer>(Integer.class, 10);
@@ -110,7 +106,6 @@
         assertThat(data, is(new Object[]{3, tile}));
     }
 
-    @Test
     public void testRemoveTile() throws InterruptedException {
         initWait("removeTile");
         mMainThreadProxy.removeTile(1, 2);
@@ -118,15 +113,15 @@
         assertThat(data, is(new Object[]{1, 2}));
     }
 
-    @Test
     public void testRefresh() throws InterruptedException {
         initWait("refresh");
+        // In this test and below the calls to mBackgroundProxy are not really made from the worker
+        // thread. That's OK since the message queue inside mBackgroundProxy is synchronized.
         mBackgroundProxy.refresh(2);
         Object[] data = waitFor("refresh");
         assertThat(data, is(new Object[]{2}));
     }
 
-    @Test
     public void testRangeUpdate() throws InterruptedException {
         initWait("updateRange");
         mBackgroundProxy.updateRange(10, 20, 5, 25, 1);
@@ -134,7 +129,6 @@
         assertThat(data, is(new Object[] {10, 20, 5, 25, 1}));
     }
 
-    @Test
     public void testLoadTile() throws InterruptedException {
         initWait("loadTile");
         mBackgroundProxy.loadTile(2, 1);
@@ -142,7 +136,6 @@
         assertThat(data, is(new Object[]{2, 1}));
     }
 
-    @Test
     public void testRecycleTile() throws InterruptedException {
         initWait("recycleTile");
         TileList.Tile<Integer> tile = new TileList.Tile<Integer>(Integer.class, 10);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
index 3889cfa..b8f6788 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
@@ -76,8 +76,13 @@
         mDataCallback.expectTilesInRange(rangeStart, rangeSize);
         mAdapter.expectItemsInRange(rangeStart, rangeSize);
 
-        mAsyncListUtil = new AsyncListUtil<String>(String.class, TILE_SIZE, mDataCallback,
-                mViewCallback);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAsyncListUtil = new AsyncListUtil<String>(
+                        String.class, TILE_SIZE, mDataCallback, mViewCallback);
+            }
+        });
 
         mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
             @Override
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java
new file mode 100644
index 0000000..4764c00
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java
@@ -0,0 +1,729 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for animation related tests.
+ */
+public class BaseRecyclerViewAnimationsTest extends BaseRecyclerViewInstrumentationTest {
+
+    protected static final boolean DEBUG = false;
+
+    protected static final String TAG = "RecyclerViewAnimationsTest";
+
+    AnimationLayoutManager mLayoutManager;
+
+    TestAdapter mTestAdapter;
+
+    public BaseRecyclerViewAnimationsTest() {
+        super(DEBUG);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    RecyclerView setupBasic(int itemCount) throws Throwable {
+        return setupBasic(itemCount, 0, itemCount);
+    }
+
+    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount)
+            throws Throwable {
+        return setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null);
+    }
+
+    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount,
+            TestAdapter testAdapter)
+            throws Throwable {
+        final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
+        recyclerView.setHasFixedSize(true);
+        if (testAdapter == null) {
+            mTestAdapter = new TestAdapter(itemCount);
+        } else {
+            mTestAdapter = testAdapter;
+        }
+        recyclerView.setAdapter(mTestAdapter);
+        recyclerView.setItemAnimator(createItemAnimator());
+        mLayoutManager = new AnimationLayoutManager();
+        recyclerView.setLayoutManager(mLayoutManager);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = firstLayoutStartIndex;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = firstLayoutItemCount;
+
+        mLayoutManager.expectLayouts(1);
+        recyclerView.expectDraw(1);
+        setRecyclerView(recyclerView);
+        mLayoutManager.waitForLayout(2);
+        recyclerView.waitForDraw(1);
+        mLayoutManager.mOnLayoutCallbacks.reset();
+        getInstrumentation().waitForIdleSync();
+        checkForMainThreadException();
+        assertEquals("extra layouts should not happen", 1, mLayoutManager.getTotalLayoutCount());
+        assertEquals("all expected children should be laid out", firstLayoutItemCount,
+                mLayoutManager.getChildCount());
+        return recyclerView;
+    }
+
+    protected RecyclerView.ItemAnimator createItemAnimator() {
+        return new DefaultItemAnimator();
+    }
+
+    public TestRecyclerView getTestRecyclerView() {
+        return (TestRecyclerView) mRecyclerView;
+    }
+
+    class AnimationLayoutManager extends TestLayoutManager {
+
+        protected int mTotalLayoutCount = 0;
+        private String log;
+
+        OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() {
+        };
+
+
+
+        @Override
+        public boolean supportsPredictiveItemAnimations() {
+            return true;
+        }
+
+        public String getLog() {
+            return log;
+        }
+
+        private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) {
+            StringBuilder builder = new StringBuilder();
+            builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done);
+            builder.append("\nViewHolders:\n");
+            for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) {
+                builder.append(vh).append("\n");
+            }
+            builder.append("scrap:\n");
+            for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
+                builder.append(vh).append("\n");
+            }
+
+            if (state.isPreLayout() && !done) {
+                log = "\n" + builder.toString();
+            } else {
+                log += "\n" + builder.toString();
+            }
+            return log;
+        }
+
+        @Override
+        public void expectLayouts(int count) {
+            super.expectLayouts(count);
+            mOnLayoutCallbacks.mLayoutCount = 0;
+        }
+
+        public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) {
+            mOnLayoutCallbacks = onLayoutCallbacks;
+        }
+
+        @Override
+        public final void onLayoutChildren(RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            try {
+                mTotalLayoutCount++;
+                prepareLog(recycler, state, false);
+                if (state.isPreLayout()) {
+                    validateOldPositions(recycler, state);
+                } else {
+                    validateClearedOldPositions(recycler, state);
+                }
+                mOnLayoutCallbacks.onLayoutChildren(recycler, this, state);
+                prepareLog(recycler, state, true);
+            } finally {
+                layoutLatch.countDown();
+            }
+        }
+
+        private void validateClearedOldPositions(RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            if (getTestRecyclerView() == null) {
+                return;
+            }
+            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
+                assertEquals("there should NOT be an old position in post layout",
+                        RecyclerView.NO_POSITION, viewHolder.mOldPosition);
+                assertEquals("there should NOT be a pre layout position in post layout",
+                        RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition);
+            }
+        }
+
+        private void validateOldPositions(RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            if (getTestRecyclerView() == null) {
+                return;
+            }
+            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
+                if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) {
+                    assertTrue("there should be an old position in pre-layout",
+                            viewHolder.mOldPosition != RecyclerView.NO_POSITION);
+                }
+            }
+        }
+
+        public int getTotalLayoutCount() {
+            return mTotalLayoutCount;
+        }
+
+        @Override
+        public boolean canScrollVertically() {
+            return true;
+        }
+
+        @Override
+        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            mOnLayoutCallbacks.onScroll(dy, recycler, state);
+            return super.scrollVerticallyBy(dy, recycler, state);
+        }
+
+        public void onPostDispatchLayout() {
+            mOnLayoutCallbacks.postDispatchLayout();
+        }
+
+        @Override
+        public void waitForLayout(long timeout, TimeUnit timeUnit) throws Throwable {
+            super.waitForLayout(timeout, timeUnit);
+            checkForMainThreadException();
+        }
+    }
+
+    abstract class OnLayoutCallbacks {
+
+        int mLayoutMin = Integer.MIN_VALUE;
+
+        int mLayoutItemCount = Integer.MAX_VALUE;
+
+        int expectedPreLayoutItemCount = -1;
+
+        int expectedPostLayoutItemCount = -1;
+
+        int mDeletedViewCount;
+
+        int mLayoutCount = 0;
+
+        void setExpectedItemCounts(int preLayout, int postLayout) {
+            expectedPreLayoutItemCount = preLayout;
+            expectedPostLayoutItemCount = postLayout;
+        }
+
+        void reset() {
+            mLayoutMin = Integer.MIN_VALUE;
+            mLayoutItemCount = Integer.MAX_VALUE;
+            expectedPreLayoutItemCount = -1;
+            expectedPostLayoutItemCount = -1;
+            mLayoutCount = 0;
+        }
+
+        void beforePreLayout(RecyclerView.Recycler recycler,
+                AnimationLayoutManager lm, RecyclerView.State state) {
+            mDeletedViewCount = 0;
+            for (int i = 0; i < lm.getChildCount(); i++) {
+                View v = lm.getChildAt(i);
+                if (lm.getLp(v).isItemRemoved()) {
+                    mDeletedViewCount++;
+                }
+            }
+        }
+
+        void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
+                RecyclerView.State state) {
+            if (DEBUG) {
+                Log.d(TAG, "item count " + state.getItemCount());
+            }
+            lm.detachAndScrapAttachedViews(recycler);
+            final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin;
+            final int count = mLayoutItemCount
+                    == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount;
+            lm.layoutRange(recycler, start, start + count);
+            assertEquals("correct # of children should be laid out",
+                    count, lm.getChildCount());
+            lm.assertVisibleItemPositions();
+        }
+
+        private void assertNoPreLayoutPosition(RecyclerView.Recycler recycler) {
+            for (RecyclerView.ViewHolder vh : recycler.mAttachedScrap) {
+                assertPreLayoutPosition(vh);
+            }
+        }
+
+        private void assertNoPreLayoutPosition(RecyclerView.LayoutManager lm) {
+            for (int i = 0; i < lm.getChildCount(); i ++) {
+                final RecyclerView.ViewHolder vh = mRecyclerView
+                        .getChildViewHolder(lm.getChildAt(i));
+                assertPreLayoutPosition(vh);
+            }
+        }
+
+        private void assertPreLayoutPosition(RecyclerView.ViewHolder vh) {
+            assertEquals("in post layout, there should not be a view holder w/ a pre "
+                    + "layout position", RecyclerView.NO_POSITION, vh.mPreLayoutPosition);
+            assertEquals("in post layout, there should not be a view holder w/ an old "
+                    + "layout position", RecyclerView.NO_POSITION, vh.mOldPosition);
+        }
+
+        void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
+                RecyclerView.State state) {
+            if (state.isPreLayout()) {
+                if (expectedPreLayoutItemCount != -1) {
+                    assertEquals("on pre layout, state should return abstracted adapter size",
+                            expectedPreLayoutItemCount, state.getItemCount());
+                }
+                beforePreLayout(recycler, lm, state);
+            } else {
+                if (expectedPostLayoutItemCount != -1) {
+                    assertEquals("on post layout, state should return real adapter size",
+                            expectedPostLayoutItemCount, state.getItemCount());
+                }
+                beforePostLayout(recycler, lm, state);
+            }
+            if (!state.isPreLayout()) {
+                assertNoPreLayoutPosition(recycler);
+            }
+            doLayout(recycler, lm, state);
+            if (state.isPreLayout()) {
+                afterPreLayout(recycler, lm, state);
+            } else {
+                afterPostLayout(recycler, lm, state);
+                assertNoPreLayoutPosition(lm);
+            }
+            mLayoutCount++;
+        }
+
+        void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
+                RecyclerView.State state) {
+        }
+
+        void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
+                RecyclerView.State state) {
+        }
+
+        void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
+                RecyclerView.State state) {
+        }
+
+        void postDispatchLayout() {
+        }
+
+        public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
+
+        }
+    }
+
+    class TestRecyclerView extends RecyclerView {
+
+        CountDownLatch drawLatch;
+
+        public TestRecyclerView(Context context) {
+            super(context);
+        }
+
+        public TestRecyclerView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+        }
+
+        @Override
+        void initAdapterManager() {
+            super.initAdapterManager();
+            mAdapterHelper.mOnItemProcessedCallback = new Runnable() {
+                @Override
+                public void run() {
+                    validatePostUpdateOp();
+                }
+            };
+        }
+
+        @Override
+        boolean isAccessibilityEnabled() {
+            return true;
+        }
+
+        public void expectDraw(int count) {
+            drawLatch = new CountDownLatch(count);
+        }
+
+        public void waitForDraw(long timeout) throws Throwable {
+            drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS);
+            assertEquals("all expected draws should happen at the expected time frame",
+                    0, drawLatch.getCount());
+        }
+
+        List<ViewHolder> collectViewHolders() {
+            List<ViewHolder> holders = new ArrayList<ViewHolder>();
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                ViewHolder holder = getChildViewHolderInt(getChildAt(i));
+                if (holder != null) {
+                    holders.add(holder);
+                }
+            }
+            return holders;
+        }
+
+
+        private void validateViewHolderPositions() {
+            final Set<Integer> existingOffsets = new HashSet<Integer>();
+            int childCount = getChildCount();
+            StringBuilder log = new StringBuilder();
+            for (int i = 0; i < childCount; i++) {
+                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
+                TestViewHolder tvh = (TestViewHolder) vh;
+                log.append(tvh.mBoundItem).append(vh)
+                        .append(" hidden:")
+                        .append(mChildHelper.mHiddenViews.contains(vh.itemView))
+                        .append("\n");
+            }
+            for (int i = 0; i < childCount; i++) {
+                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
+                if (vh.isInvalid()) {
+                    continue;
+                }
+                if (vh.getLayoutPosition() < 0) {
+                    LayoutManager lm = getLayoutManager();
+                    for (int j = 0; j < lm.getChildCount(); j ++) {
+                        assertNotSame("removed view holder should not be in LM's child list",
+                                vh.itemView, lm.getChildAt(j));
+                    }
+                } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) {
+                    if (!existingOffsets.add(vh.getLayoutPosition())) {
+                        throw new IllegalStateException("view holder position conflict for "
+                                + "existing views " + vh + "\n" + log);
+                    }
+                }
+            }
+        }
+
+        void validatePostUpdateOp() {
+            try {
+                validateViewHolderPositions();
+                if (super.mState.isPreLayout()) {
+                    validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager());
+                }
+                validateAdapterPosition((AnimationLayoutManager) getLayoutManager());
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+        }
+
+
+
+        private void validateAdapterPosition(AnimationLayoutManager lm) {
+            for (ViewHolder vh : collectViewHolders()) {
+                if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) {
+                    assertEquals("adapter position calculations should match view holder "
+                                    + "pre layout:" + mState.isPreLayout()
+                                    + " positions\n" + vh + "\n" + lm.getLog(),
+                            mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition);
+                }
+            }
+        }
+
+        // ensures pre layout positions are continuous block. This is not necessarily a case
+        // but valid in test RV
+        private void validatePreLayoutSequence(AnimationLayoutManager lm) {
+            Set<Integer> preLayoutPositions = new HashSet<Integer>();
+            for (ViewHolder vh : collectViewHolders()) {
+                assertTrue("pre layout positions should be distinct " + lm.getLog(),
+                        preLayoutPositions.add(vh.mPreLayoutPosition));
+            }
+            int minPos = Integer.MAX_VALUE;
+            for (Integer pos : preLayoutPositions) {
+                if (pos < minPos) {
+                    minPos = pos;
+                }
+            }
+            for (int i = 1; i < preLayoutPositions.size(); i++) {
+                assertNotNull("next position should exist " + lm.getLog(),
+                        preLayoutPositions.contains(minPos + i));
+            }
+        }
+
+        @Override
+        protected void dispatchDraw(Canvas canvas) {
+            super.dispatchDraw(canvas);
+            if (drawLatch != null) {
+                drawLatch.countDown();
+            }
+        }
+
+        @Override
+        void dispatchLayout() {
+            try {
+                super.dispatchLayout();
+                if (getLayoutManager() instanceof AnimationLayoutManager) {
+                    ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout();
+                }
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+
+        }
+
+
+    }
+
+    abstract class AdapterOps {
+
+        final public void run(TestAdapter adapter) throws Throwable {
+            onRun(adapter);
+        }
+
+        abstract void onRun(TestAdapter testAdapter) throws Throwable;
+    }
+
+    static class CollectPositionResult {
+
+        // true if found in scrap
+        public RecyclerView.ViewHolder scrapResult;
+
+        public RecyclerView.ViewHolder adapterResult;
+
+        static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) {
+            CollectPositionResult cpr = new CollectPositionResult();
+            cpr.scrapResult = viewHolder;
+            return cpr;
+        }
+
+        static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) {
+            CollectPositionResult cpr = new CollectPositionResult();
+            cpr.adapterResult = viewHolder;
+            return cpr;
+        }
+
+        @Override
+        public String toString() {
+            return "CollectPositionResult{" +
+                    "scrapResult=" + scrapResult +
+                    ", adapterResult=" + adapterResult +
+                    '}';
+        }
+    }
+
+    static class PositionConstraint {
+
+        public static enum Type {
+            scrap,
+            adapter,
+            adapterScrap /*first pass adapter, second pass scrap*/
+        }
+
+        Type mType;
+
+        int mOldPos; // if VH
+
+        int mPreLayoutPos;
+
+        int mPostLayoutPos;
+
+        int mValidateCount = 0;
+
+        public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) {
+            PositionConstraint constraint = new PositionConstraint();
+            constraint.mType = Type.scrap;
+            constraint.mOldPos = oldPos;
+            constraint.mPreLayoutPos = preLayoutPos;
+            constraint.mPostLayoutPos = postLayoutPos;
+            return constraint;
+        }
+
+        public static PositionConstraint adapterScrap(int preLayoutPos, int position) {
+            PositionConstraint constraint = new PositionConstraint();
+            constraint.mType = Type.adapterScrap;
+            constraint.mOldPos = RecyclerView.NO_POSITION;
+            constraint.mPreLayoutPos = preLayoutPos;
+            constraint.mPostLayoutPos = position;// adapter pos does not change
+            return constraint;
+        }
+
+        public static PositionConstraint adapter(int position) {
+            PositionConstraint constraint = new PositionConstraint();
+            constraint.mType = Type.adapter;
+            constraint.mPreLayoutPos = RecyclerView.NO_POSITION;
+            constraint.mOldPos = RecyclerView.NO_POSITION;
+            constraint.mPostLayoutPos = position;// adapter pos does not change
+            return constraint;
+        }
+
+        public void assertValidate() {
+            int expectedValidate = 0;
+            if (mPreLayoutPos >= 0) {
+                expectedValidate ++;
+            }
+            if (mPostLayoutPos >= 0) {
+                expectedValidate ++;
+            }
+            assertEquals("should run all validates", expectedValidate, mValidateCount);
+        }
+
+        @Override
+        public String toString() {
+            return "Cons{" +
+                    "t=" + mType.name() +
+                    ", old=" + mOldPos +
+                    ", pre=" + mPreLayoutPos +
+                    ", post=" + mPostLayoutPos +
+                    '}';
+        }
+
+        public void validate(RecyclerView.State state, CollectPositionResult result, String log) {
+            mValidateCount ++;
+            assertNotNull(this + ": result should not be null\n" + log, result);
+            RecyclerView.ViewHolder viewHolder;
+            if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) {
+                assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult);
+                viewHolder = result.scrapResult;
+            } else {
+                assertNotNull(this + ": result should come from adapter\n"  + log,
+                        result.adapterResult);
+                assertEquals(this + ": old position should be none when it came from adapter\n" + log,
+                        RecyclerView.NO_POSITION, result.adapterResult.getOldPosition());
+                viewHolder = result.adapterResult;
+            }
+            if (state.isPreLayout()) {
+                assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos,
+                        viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition :
+                                viewHolder.mPreLayoutPosition);
+                assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos,
+                        viewHolder.getLayoutPosition());
+                if (mType == Type.scrap) {
+                    assertEquals(this + ": old position should match\n" + log, mOldPos,
+                            result.scrapResult.getOldPosition());
+                }
+            } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult
+                    .isRemoved()) {
+                assertEquals(this + ": post-layout position should match\n" + log + "\n\n"
+                        + viewHolder, mPostLayoutPos, viewHolder.getLayoutPosition());
+            }
+        }
+    }
+
+    static class LoggingInfo extends RecyclerView.ItemAnimator.ItemHolderInfo {
+        final RecyclerView.ViewHolder viewHolder;
+        @RecyclerView.ItemAnimator.AdapterChanges
+        final int changeFlags;
+        final List<Object> payloads;
+
+        LoggingInfo(RecyclerView.ViewHolder viewHolder, int changeFlags, List<Object> payloads) {
+            this.viewHolder = viewHolder;
+            this.changeFlags = changeFlags;
+            if (payloads != null) {
+                this.payloads = new ArrayList<>();
+                this.payloads.addAll(payloads);
+            } else {
+                this.payloads = null;
+            }
+            setFrom(viewHolder);
+        }
+    }
+
+    static class AnimateChange extends AnimateLogBase {
+
+        final RecyclerView.ViewHolder newHolder;
+
+        public AnimateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
+                LoggingInfo pre, LoggingInfo post) {
+            super(oldHolder, pre, post);
+            this.newHolder = newHolder;
+        }
+    }
+
+    static class AnimatePersistence extends AnimateLogBase {
+
+        public AnimatePersistence(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+                LoggingInfo post) {
+            super(viewHolder, pre, post);
+        }
+    }
+
+    static class AnimateAppearance extends AnimateLogBase {
+        public AnimateAppearance(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+                LoggingInfo post) {
+            super(viewHolder, pre, post);
+        }
+    }
+
+    static class AnimateDisappearance extends AnimateLogBase {
+        public AnimateDisappearance(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+                LoggingInfo post) {
+            super(viewHolder, pre, post);
+        }
+    }
+    static class AnimateLogBase {
+
+        final RecyclerView.ViewHolder viewHolder;
+        final LoggingInfo preInfo;
+        final LoggingInfo postInfo;
+
+        public AnimateLogBase(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+                LoggingInfo postInfo) {
+            this.viewHolder = viewHolder;
+            this.preInfo = pre;
+            this.postInfo = postInfo;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            AnimateLogBase that = (AnimateLogBase) o;
+
+            if (viewHolder != null ? !viewHolder.equals(that.viewHolder)
+                    : that.viewHolder != null) {
+                return false;
+            }
+            if (preInfo != null ? !preInfo.equals(that.preInfo) : that.preInfo != null) {
+                return false;
+            }
+            return !(postInfo != null ? !postInfo.equals(that.postInfo) : that.postInfo != null);
+
+        }
+
+        @Override
+        public int hashCode() {
+            int result = viewHolder != null ? viewHolder.hashCode() : 0;
+            result = 31 * result + (preInfo != null ? preInfo.hashCode() : 0);
+            result = 31 * result + (postInfo != null ? postInfo.hashCode() : 0);
+            return result;
+        }
+    }
+}
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 2659ef2..c5f3408 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -164,7 +164,7 @@
         } catch (Exception e) {
             throw e;
         } catch (Throwable throwable) {
-            throw new Exception(throwable);
+            throw new Exception(Log.getStackTraceString(throwable));
         }
     }
 
@@ -202,19 +202,23 @@
         mRecyclerView = null;
     }
 
-    void waitForAnimations(int seconds) throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(2);
-        boolean running = mRecyclerView.mItemAnimator
-                .isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
-                    @Override
-                    public void onAnimationsFinished() {
-                        latch.countDown();
-                    }
-                });
-        if (running) {
-            latch.countDown();
-            latch.await(seconds, TimeUnit.SECONDS);
-        }
+    void waitForAnimations(int seconds) throws Throwable {
+        final CountDownLatch latch = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.mItemAnimator
+                        .isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
+                            @Override
+                            public void onAnimationsFinished() {
+                                latch.countDown();
+                            }
+                        });
+            }
+        });
+
+        assertTrue("animations didn't finish on expected time of " + seconds + " seconds",
+                latch.await(seconds, TimeUnit.SECONDS));
     }
 
     public boolean requestFocus(final View view) {
@@ -548,6 +552,7 @@
         int mAdapterIndex;
 
         final String mText;
+        int mType = 0;
 
         Item(int adapterIndex, String text) {
             mAdapterIndex = adapterIndex;
@@ -584,6 +589,11 @@
         }
 
         @Override
+        public int getItemViewType(int position) {
+            return getItemAt(position).mType;
+        }
+
+        @Override
         public void onViewAttachedToWindow(TestViewHolder holder) {
             super.onViewAttachedToWindow(holder);
             mAttachmentCounter.onViewAttached(holder);
@@ -713,6 +723,16 @@
             });
         }
 
+        public void changeAndNotifyWithPayload(final int start, final int count,
+                final Object payload) throws Throwable {
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    notifyItemRangeChanged(start, count, payload);
+                }
+            });
+        }
+
         public void changePositionsAndNotify(final int... positions) throws Throwable {
             runTestOnUiThread(new Runnable() {
                 @Override
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java
new file mode 100644
index 0000000..8163310
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.AndroidTestCase;
+import android.test.mock.MockContext;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ChildHelperTest extends AndroidTestCase {
+    LoggingCallback  mLoggingCallback;
+    ChildHelper mChildHelper;
+
+    @Before
+    public void prepare() throws Exception {
+        setUp();
+        setContext(InstrumentationRegistry.getContext());
+        mLoggingCallback = new LoggingCallback();
+        mChildHelper = new ChildHelper(mLoggingCallback);
+    }
+
+    private RecyclerView.ViewHolder vh() {
+        View view = new View(mContext);
+        RecyclerViewBasicTest.MockViewHolder mockViewHolder
+                = new RecyclerViewBasicTest.MockViewHolder(view);
+        RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(0 , 0);
+        lp.mViewHolder = mockViewHolder;
+        view.setLayoutParams(lp);
+        return mockViewHolder;
+    }
+
+    @Test
+    public void testAddChild() {
+        RecyclerView.ViewHolder vh = vh();
+        mChildHelper.addView(vh.itemView, false);
+        assertEquals(1, mLoggingCallback.getChildCount());
+        assertFalse(mChildHelper.isHidden(vh.itemView));
+        assertEquals(0, mLoggingCallback.mOnEnteredHiddenState.size());
+    }
+
+    @Test
+    public void testAddChildHidden() {
+        RecyclerView.ViewHolder vh = vh();
+        mChildHelper.addView(vh.itemView, true);
+        assertEquals(1, mLoggingCallback.getChildCount());
+        assertTrue(mChildHelper.isHidden(vh.itemView));
+        assertTrue(mLoggingCallback.mOnEnteredHiddenState.contains(vh.itemView));
+    }
+
+    @Test
+    public void testAddChildAndHide() {
+        RecyclerView.ViewHolder vh = vh();
+        mChildHelper.addView(vh.itemView, false);
+        mChildHelper.hide(vh.itemView);
+        assertTrue(mChildHelper.isHidden(vh.itemView));
+        mChildHelper.unhide(vh.itemView);
+        assertFalse(mChildHelper.isHidden(vh.itemView));
+    }
+
+    @Test
+    public void testFindHiddenNonRemoved() {
+        RecyclerView.ViewHolder vh = vh();
+        vh.mPosition = 12;
+        mChildHelper.addView(vh.itemView, true);
+        assertSame(vh.itemView,
+                mChildHelper.findHiddenNonRemovedView(12, RecyclerView.INVALID_TYPE));
+    }
+
+    @Test
+    public void testFindHiddenRemoved() {
+        RecyclerView.ViewHolder vh = vh();
+        vh.mPosition = 12;
+        vh.addFlags(RecyclerView.ViewHolder.FLAG_REMOVED);
+        mChildHelper.addView(vh.itemView, true);
+        assertNull(mChildHelper.findHiddenNonRemovedView(12, RecyclerView.INVALID_TYPE));
+    }
+
+    private static class LoggingCallback implements ChildHelper.Callback {
+        List<View> mViews = new ArrayList<>();
+        List<View> mDetached = new ArrayList<>();
+        List<View> mOnEnteredHiddenState = new ArrayList<>();
+        List<View> mOnExitedHiddenState = new ArrayList<>();
+        @Override
+        public int getChildCount() {
+            return mViews.size();
+        }
+
+        @Override
+        public void addView(View child, int index) {
+            mViews.add(index, child);
+        }
+
+        @Override
+        public int indexOfChild(View view) {
+            return mViews.indexOf(view);
+        }
+
+        private boolean validateIndex(int index) {
+            return index < getChildCount() && index >= 0;
+        }
+
+        @Override
+        public void removeViewAt(int index) {
+            if (validateIndex(index)) {
+                mViews.remove(index);
+            }
+        }
+
+        @Override
+        public View getChildAt(int offset) {
+            if (validateIndex(offset)) {
+                return mViews.remove(offset);
+            }
+            return null;
+        }
+
+        @Override
+        public void removeAllViews() {
+            mViews.clear();
+        }
+
+        @Override
+        public RecyclerView.ViewHolder getChildViewHolder(View view) {
+            return RecyclerView.getChildViewHolderInt(view);
+        }
+
+        @Override
+        public void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams) {
+            assertTrue(mDetached.remove(child));
+            addView(child, index);
+        }
+
+        @Override
+        public void detachViewFromParent(int offset) {
+            mDetached.add(getChildAt(offset));
+        }
+
+        @Override
+        public void onEnteredHiddenState(View child) {
+            mOnEnteredHiddenState.add(child);
+        }
+
+        @Override
+        public void onLeftHiddenState(View child) {
+            mOnExitedHiddenState.add(child);
+        }
+
+        public void clearHiddenStateLog() {
+            mOnExitedHiddenState.clear();
+            mOnEnteredHiddenState.clear();
+        }
+    }
+}
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 46833ca..5010be9 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
@@ -58,10 +58,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mAnimator = new DefaultItemAnimator();
-        mAdapter = new Adapter(20);
-        mDummyParent = getActivity().mContainer;
-        mAnimator.setListener(new RecyclerView.ItemAnimator.ItemAnimatorListener() {
+        mAnimator = new DefaultItemAnimator() {
             @Override
             public void onRemoveFinished(RecyclerView.ViewHolder item) {
                 try {
@@ -93,7 +90,7 @@
             }
 
             @Override
-            public void onChangeFinished(RecyclerView.ViewHolder item) {
+            public void onChangeFinished(RecyclerView.ViewHolder item, boolean oldItem) {
                 try {
                     assertTrue(mChangeFinished.add(item));
                     onFinished(item);
@@ -106,7 +103,9 @@
                 assertNotNull(mExpectedItems.remove(item));
                 mExpectedItemCount.release(1);
             }
-        });
+        };
+        mAdapter = new Adapter(20);
+        mDummyParent = getActivity().mContainer;
     }
 
     void checkForMainThreadException() throws Throwable {
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 ca7b0a4..6192c66 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -18,9 +18,9 @@
 
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.Debug;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.test.UiThreadTest;
 import android.util.Log;
 import android.util.SparseIntArray;
 import android.view.View;
@@ -86,6 +86,27 @@
         mGlm.waitForLayout(2);
     }
 
+    @UiThreadTest
+    public void testScrollWithoutLayout() throws Throwable {
+        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
+        mGlm.expectLayout(1);
+        setRecyclerView(recyclerView);
+        mGlm.setSpanCount(5);
+        recyclerView.scrollBy(0, 10);
+    }
+
+    public void testScrollWithoutLayoutAfterInvalidate() throws Throwable {
+        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
+        waitForFirstLayout(recyclerView);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGlm.setSpanCount(5);
+                recyclerView.scrollBy(0, 10);
+            }
+        });
+    }
+
     public void testPredictiveSpanLookup1() throws Throwable {
         predictiveSpanLookupTest(0, false);
     }
@@ -291,7 +312,7 @@
                 return 3;
             }
         });
-        rv.getItemAnimator().setSupportsChangeAnimations(true);
+        ((SimpleItemAnimator)rv.getItemAnimator()).setSupportsChangeAnimations(true);
         waitForFirstLayout(rv);
         View lastView = rv.getChildAt(rv.getChildCount() - 1);
         final int lastPos = rv.getChildAdapterPosition(lastView);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java b/v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java
new file mode 100644
index 0000000..b3fbae4
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+/**
+ * Helper class for tests to check internals of ViewInfoStore
+ */
+public class InfoStoreTrojan {
+    static int sizeOfPreLayout(ViewInfoStore store) {
+        return sizeOf(store, ViewInfoStore.InfoRecord.FLAG_PRE);
+    }
+    static int sizeOfPostLayout(ViewInfoStore store) {
+        return sizeOf(store, ViewInfoStore.InfoRecord.FLAG_POST);
+    }
+    static int sizeOf(ViewInfoStore store, int flags) {
+        int cnt = 0;
+        final int size = store.mLayoutHolderMap.size();
+        for (int i = 0; i < size; i ++) {
+            ViewInfoStore.InfoRecord record = store.mLayoutHolderMap.valueAt(i);
+            if ((record.flags & flags) != 0) {
+                cnt ++;
+            }
+        }
+        return cnt;
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java
new file mode 100644
index 0000000..5733e720
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java
@@ -0,0 +1,541 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_CHANGED;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_MOVED;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_REMOVED;
+
+/**
+ * Includes tests for the new RecyclerView animations API (v2).
+ */
+public class ItemAnimatorV2ApiTest extends BaseRecyclerViewAnimationsTest {
+    @Override
+    protected RecyclerView.ItemAnimator createItemAnimator() {
+        return mAnimator;
+    }
+
+    public void testChangeMovedOutside() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder target = mRecyclerView.findViewHolderForAdapterPosition(9);
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+        mTestAdapter.changeAndNotify(9, 1);
+        mLayoutManager.waitForLayout(2);
+        // changed item shold not be laid out and should just receive disappear
+        LoggingInfo pre = mAnimator.preLayoutInfoMap.get(target);
+        assertNotNull("test sanity", pre);
+        assertNull("test sanity", mAnimator.postLayoutInfoMap.get(target));
+        assertTrue(mAnimator.animateChangeList.isEmpty());
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+        assertEquals(new AnimateDisappearance(target, pre, null),
+                mAnimator.animateDisappearanceList.get(0));
+        // This is kind of problematic because layout manager will never layout the updated
+        // version of this view since it went out of bounds and it won't show up in scrap.
+        // I don't think we can do much better since other option is to bind a fresh view
+    }
+
+    public void testSimpleAdd() throws Throwable {
+        setupBasic(10);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.addAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        assertEquals(1, mAnimator.animateAppearanceList.size());
+        AnimateAppearance log = mAnimator.animateAppearanceList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertNull(log.preInfo);
+        assertEquals(0, log.postInfo.changeFlags);
+        // the first two should not receive anything
+        for (int i = 0; i < 2; i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    public void testSimpleRemove() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_REMOVED, log.preInfo.changeFlags);
+        // the first two should not receive anything
+        for (int i = 0; i < 2; i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    public void testSimpleUpdate() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        assertEquals(1, mAnimator.animateChangeList.size());
+        AnimateChange log = mAnimator.animateChangeList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertSame(vh, log.newHolder);
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, log.postInfo.changeFlags);
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    public void testUpdateWithDuplicateViewHolder() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+                assertSame(viewHolder, vh);
+                return false;
+            }
+        };
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        assertNotSame(vh, newVh);
+        assertEquals(1, mAnimator.animateChangeList.size());
+        AnimateChange log = mAnimator.animateChangeList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertSame(newVh, log.newHolder);
+        assertNull(vh.itemView.getParent());
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, log.postInfo.changeFlags);
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    public void testUpdateWithOneDuplicateAndOneInPlace() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder replaced = mRecyclerView.findViewHolderForAdapterPosition(2);
+        final RecyclerView.ViewHolder reused = mRecyclerView.findViewHolderForAdapterPosition(3);
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+                if (viewHolder == replaced) {
+                    return false;
+                } else if (viewHolder == reused) {
+                    return true;
+                }
+                fail("unpexpected view");
+                return false;
+            }
+        };
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(2, 2);
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+
+        assertNotSame(replaced, newVh);
+        assertSame(reused, mRecyclerView.findViewHolderForAdapterPosition(3));
+
+        assertEquals(2, mAnimator.animateChangeList.size());
+        AnimateChange logReplaced = null, logReused = null;
+        for (AnimateChange change : mAnimator.animateChangeList) {
+            if (change.newHolder == change.viewHolder) {
+                logReused = change;
+            } else {
+                logReplaced = change;
+            }
+        }
+        assertNotNull(logReplaced);
+        assertNotNull(logReused);
+        assertSame(replaced, logReplaced.viewHolder);
+        assertSame(newVh, logReplaced.newHolder);
+        assertSame(reused, logReused.viewHolder);
+        assertSame(reused, logReused.newHolder);
+
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(replaced));
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(reused));
+
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(reused));
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(replaced));
+
+        assertEquals(FLAG_CHANGED, logReplaced.preInfo.changeFlags);
+        assertEquals(FLAG_CHANGED, logReused.preInfo.changeFlags);
+
+        assertEquals(0, logReplaced.postInfo.changeFlags);
+        assertEquals(0, logReused.postInfo.changeFlags);
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2 || i == 3) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    public void testChangeToDisappear() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(9);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(9, 1);
+        mLayoutManager.waitForLayout(2);
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(9, mAnimator.animatePersistenceList.size());
+        checkForMainThreadException();
+    }
+
+    public void testUpdatePayload() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        mLayoutManager.expectLayouts(2);
+        Object payload = new Object();
+        mTestAdapter.changeAndNotifyWithPayload(2, 1, payload);
+        mLayoutManager.waitForLayout(2);
+        assertEquals(1, mAnimator.animateChangeList.size());
+        AnimateChange log = mAnimator.animateChangeList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertSame(vh, log.newHolder);
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, log.postInfo.changeFlags);
+        assertNotNull(log.preInfo.payloads);
+        assertTrue(log.preInfo.payloads.contains(payload));
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    public void testNotifyDataSetChanged() throws Throwable {
+        TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        mTestAdapter.dispatchDataSetChanged();
+        mLayoutManager.waitForLayout(2);
+        assertEquals(10, mAnimator.animateChangeList.size());
+        for (AnimateChange change : mAnimator.animateChangeList) {
+            assertNotNull(change.preInfo);
+            assertNotNull(change.postInfo);
+            assertSame(change.preInfo.viewHolder, change.postInfo.viewHolder);
+        }
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+    }
+
+    public void testNotifyDataSetChangedWithoutStableIds() throws Throwable {
+        TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(false);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        mTestAdapter.dispatchDataSetChanged();
+        mLayoutManager.waitForLayout(2);
+        assertEquals(0, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+    }
+
+    public void testNotifyDataSetChangedWithAppearing() throws Throwable {
+        notifyDataSetChangedWithAppearing(false);
+    }
+
+    public void testNotifyDataSetChangedWithAppearingNotifyBoth() throws Throwable {
+        notifyDataSetChangedWithAppearing(true);
+    }
+
+    public void notifyDataSetChangedWithAppearing(final boolean notifyBoth) throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (notifyBoth) {
+                        adapter.addAndNotify(2, 2);
+                    } else {
+                        adapter.mItems.add(2, new Item(2, "custom 1"));
+                        adapter.mItems.add(3, new Item(3, "custom 2"));
+                    }
+
+                    adapter.notifyDataSetChanged();
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        assertEquals(10, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(2, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+    }
+
+    public void testNotifyDataSetChangedWithDispappearing() throws Throwable {
+        notifyDataSetChangedWithDispappearing(false);
+    }
+
+    public void testNotifyDataSetChangedWithDispappearingNotifyBoth() throws Throwable {
+        notifyDataSetChangedWithDispappearing(true);
+    }
+
+    public void notifyDataSetChangedWithDispappearing(final boolean notifyBoth) throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (notifyBoth) {
+                        adapter.deleteAndNotify(2, 2);
+                    } else {
+                        adapter.mItems.remove(2);
+                        adapter.mItems.remove(2);
+                    }
+                    adapter.notifyDataSetChanged();
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        assertEquals(8, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(2, mAnimator.animateDisappearanceList.size());
+    }
+
+    public void testNotifyUpdateWithChangedAdapterType() throws Throwable {
+        final AtomicInteger itemType = new AtomicInteger(1);
+        final TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public int getItemViewType(int position) {
+                return position == 2 ? itemType.get() : 20;
+            }
+        };
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+                return viewHolder != vh;
+            }
+        };
+
+        mLayoutManager.expectLayouts(1);
+        itemType.set(3);
+        adapter.dispatchDataSetChanged();
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        // TODO we should be able to map old type to the new one but doing that change has some
+        // recycling side effects.
+        assertEquals(9, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(1, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+        assertNotSame(vh, newVh);
+        for (AnimateChange change : mAnimator.animateChangeList) {
+            if (change.viewHolder == vh) {
+                assertSame(change.newHolder, newVh);
+                assertSame(change.viewHolder, vh);
+            } else {
+                assertSame(change.newHolder, change.viewHolder);
+            }
+        }
+    }
+
+    LoggingV2Animator mAnimator = new LoggingV2Animator();
+
+    class LoggingV2Animator extends RecyclerView.ItemAnimator {
+
+        CanReUseCallback canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+                return true;
+            }
+        };
+        Map<RecyclerView.ViewHolder, LoggingInfo> preLayoutInfoMap = new HashMap<>();
+        Map<RecyclerView.ViewHolder, LoggingInfo> postLayoutInfoMap = new HashMap<>();
+
+        List<AnimateAppearance> animateAppearanceList = new ArrayList<>();
+        List<AnimateDisappearance> animateDisappearanceList = new ArrayList<>();
+        List<AnimatePersistence> animatePersistenceList = new ArrayList<>();
+        List<AnimateChange> animateChangeList = new ArrayList<>();
+
+        @Override
+        public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
+            return canReUseCallback.canReUse(viewHolder);
+        }
+
+        @NonNull
+        @Override
+        public ItemHolderInfo recordPreLayoutInformation(@NonNull RecyclerView.State state,
+                @NonNull RecyclerView.ViewHolder viewHolder,
+                @AdapterChanges int changeFlags, @NonNull List<Object> payloads) {
+            LoggingInfo loggingInfo = new LoggingInfo(viewHolder, changeFlags, payloads);
+            preLayoutInfoMap.put(viewHolder, loggingInfo);
+            return loggingInfo;
+        }
+
+        @NonNull
+        @Override
+        public ItemHolderInfo recordPostLayoutInformation(@NonNull RecyclerView.State state,
+                @NonNull RecyclerView.ViewHolder viewHolder) {
+            LoggingInfo loggingInfo = new LoggingInfo(viewHolder, 0, null);
+            postLayoutInfoMap.put(viewHolder, loggingInfo);
+            return loggingInfo;
+        }
+
+        @Override
+        public boolean animateDisappearance(@NonNull RecyclerView.ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preLayoutInfo,
+                @Nullable ItemHolderInfo postLayoutInfo) {
+            animateDisappearanceList.add(new AnimateDisappearance(viewHolder,
+                    (LoggingInfo) preLayoutInfo, (LoggingInfo) postLayoutInfo));
+            assertSame(preLayoutInfoMap.get(viewHolder), preLayoutInfo);
+            assertSame(postLayoutInfoMap.get(viewHolder), postLayoutInfo);
+            dispatchAnimationFinished(viewHolder);
+
+            return false;
+        }
+
+        @Override
+        public boolean animateAppearance(@NonNull RecyclerView.ViewHolder viewHolder,
+                ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+            animateAppearanceList.add(
+                    new AnimateAppearance(viewHolder, (LoggingInfo) preInfo, (LoggingInfo) postInfo));
+            assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
+            assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
+            dispatchAnimationFinished(viewHolder);
+            return false;
+        }
+
+        @Override
+        public boolean animatePersistence(@NonNull RecyclerView.ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+            animatePersistenceList.add(new AnimatePersistence(viewHolder, (LoggingInfo) preInfo,
+                    (LoggingInfo) postInfo));
+            dispatchAnimationFinished(viewHolder);
+            assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
+            assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
+            return false;
+        }
+
+        @Override
+        public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder,
+                @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo,
+                @NonNull ItemHolderInfo postInfo) {
+            animateChangeList.add(new AnimateChange(oldHolder, newHolder, (LoggingInfo) preInfo,
+                    (LoggingInfo) postInfo));
+            if (oldHolder != null) {
+                dispatchAnimationFinished(oldHolder);
+                assertSame(preLayoutInfoMap.get(oldHolder), preInfo);
+            }
+            if (newHolder != null && oldHolder != newHolder) {
+                dispatchAnimationFinished(newHolder);
+                assertSame(postLayoutInfoMap.get(newHolder), postInfo);
+            }
+
+            return false;
+        }
+
+        @Override
+        public void runPendingAnimations() {
+
+        }
+
+        @Override
+        public void endAnimation(RecyclerView.ViewHolder item) {
+        }
+
+        @Override
+        public void endAnimations() {
+
+        }
+
+        @Override
+        public boolean isRunning() {
+            return false;
+        }
+    }
+
+    interface CanReUseCallback {
+
+        boolean canReUse(RecyclerView.ViewHolder viewHolder);
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java b/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java
index 04031d4..9bbdd4b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java
@@ -13,9 +13,16 @@
 
 package android.support.v7.widget;
 
+import android.support.annotation.NonNull;
+
 import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimateDisappearance;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimateChange;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimatePersistence;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimateAppearance;
 
 public class LoggingItemAnimator extends DefaultItemAnimator {
 
@@ -29,8 +36,58 @@
 
     final ArrayList<RecyclerView.ViewHolder> mChangeNewVHs = new ArrayList<RecyclerView.ViewHolder>();
 
+    List<AnimateAppearance> mAnimateAppearanceList = new ArrayList<>();
+    List<AnimateDisappearance> mAnimateDisappearanceList = new ArrayList<>();
+    List<AnimatePersistence> mAnimatePersistenceList = new ArrayList<>();
+    List<AnimateChange> mAnimateChangeList = new ArrayList<>();
+
     CountDownLatch mWaitForPendingAnimations;
 
+    public boolean contains(RecyclerView.ViewHolder viewHolder,
+            List<? extends BaseRecyclerViewAnimationsTest.AnimateLogBase> list) {
+        for (BaseRecyclerViewAnimationsTest.AnimateLogBase log : list) {
+            if (log.viewHolder == viewHolder) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean animateDisappearance(@NonNull RecyclerView.ViewHolder viewHolder,
+            @NonNull ItemHolderInfo preLayoutInfo, ItemHolderInfo postLayoutInfo) {
+        mAnimateDisappearanceList
+                .add(new AnimateDisappearance(viewHolder, null, null));
+        return super.animateDisappearance(viewHolder, preLayoutInfo, postLayoutInfo);
+    }
+
+    @Override
+    public boolean animateAppearance(@NonNull RecyclerView.ViewHolder viewHolder,
+            ItemHolderInfo preLayoutInfo,
+            @NonNull ItemHolderInfo postLayoutInfo) {
+        mAnimateAppearanceList
+                .add(new AnimateAppearance(viewHolder, null, null));
+        return super.animateAppearance(viewHolder, preLayoutInfo, postLayoutInfo);
+    }
+
+    @Override
+    public boolean animatePersistence(@NonNull RecyclerView.ViewHolder viewHolder,
+            @NonNull ItemHolderInfo preInfo,
+            @NonNull ItemHolderInfo postInfo) {
+        mAnimatePersistenceList
+                .add(new AnimatePersistence(viewHolder, null, null));
+        return super.animatePersistence(viewHolder, preInfo, postInfo);
+    }
+
+    @Override
+    public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder,
+            @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo,
+            @NonNull ItemHolderInfo postInfo) {
+        mAnimateChangeList
+                .add(new AnimateChange(oldHolder, newHolder, null, null));
+        return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
+    }
+
     @Override
     public void runPendingAnimations() {
         if (mWaitForPendingAnimations != null) {
@@ -84,5 +141,9 @@
         mMoveVHs.clear();
         mChangeOldVHs.clear();
         mChangeNewVHs.clear();
+        mAnimateChangeList.clear();
+        mAnimatePersistenceList.clear();
+        mAnimateAppearanceList.clear();
+        mAnimateDisappearanceList.clear();
     }
 }
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
index 119ad80..0b9ef15 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
@@ -16,11 +16,9 @@
 
 package android.support.v7.widget;
 
-import android.content.Context;
-import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.os.Debug;
 import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -31,65 +29,315 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class RecyclerViewAnimationsTest extends BaseRecyclerViewInstrumentationTest {
+/**
+ * Tests for {@link SimpleItemAnimator} API.
+ */
+public class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest {
 
-    private static final boolean DEBUG = false;
+    final List<TestViewHolder> recycledVHs = new ArrayList<>();
 
-    private static final String TAG = "RecyclerViewAnimationsTest";
+    public void testDontLayoutReusedViewWithoutPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    final TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+                    @Override
+                    void beforePreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager lm, RecyclerView.State state) {
+                        fail("pre layout is not expected");
+                    }
 
-    AnimationLayoutManager mLayoutManager;
+                    @Override
+                    void beforePostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        mLayoutItemCount = 7;
+                        View targetView = recycler
+                                .getViewForPosition(target.getAdapterPosition());
+                        assertSame(targetView, target.itemView);
+                        super.beforePostLayout(recycler, layoutManager, state);
+                    }
 
-    TestAdapter mTestAdapter;
+                    @Override
+                    void afterPostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        super.afterPostLayout(recycler, layoutManager, state);
+                        assertNull("test sanity. this view should not be re-laid out in post "
+                                + "layout", target.itemView.getParent());
+                    }
+                };
+                mLayoutManager.expectLayouts(1);
+                mLayoutManager.requestSimpleAnimationsInNextLayout();
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+                checkForMainThreadException();
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                // This is a LayoutManager problem if it asked for the view but didn't properly
+                // lay it out. It will move to disappearance
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                waitForAnimations(5);
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
 
-    public RecyclerViewAnimationsTest() {
-        super(DEBUG);
+    public void testDontLayoutReusedViewWithPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    final TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+                    @Override
+                    void beforePreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager lm, RecyclerView.State state) {
+                        mLayoutItemCount = 9;
+                        super.beforePreLayout(recycler, lm, state);
+                    }
+
+                    @Override
+                    void beforePostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        mLayoutItemCount = 7;
+                        super.beforePostLayout(recycler, layoutManager, state);
+                    }
+
+                    @Override
+                    void afterPostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        super.afterPostLayout(recycler, layoutManager, state);
+                        assertNull("test sanity. this view should not be re-laid out in post "
+                                + "layout", target.itemView.getParent());
+                    }
+                };
+                mLayoutManager.expectLayouts(2);
+                mTestAdapter.deleteAndNotify(1, 1);
+                mLayoutManager.waitForLayout(2);
+                checkForMainThreadException();
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                // This is a LayoutManager problem if it asked for the view but didn't properly
+                // lay it out. It will move to disappearance.
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                waitForAnimations(5);
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    public void testReuseHiddenViewWithoutPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                mLayoutManager.requestSimpleAnimationsInNextLayout();
+                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    public void testReuseHiddenViewWithoutAnimations() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    public void testReuseHiddenViewWithPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(2);
+                mTestAdapter.deleteAndNotify(2, 1);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                // This LM does not layout the additional item so it does predictive wrong.
+                // We should still handle it and animate persistence for this item
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(itemAnimator.mMoveVHs.contains(target));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    public void testReuseHiddenViewWithProperPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+                    @Override
+                    void beforePreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager lm, RecyclerView.State state) {
+                        mLayoutItemCount = 9;
+                        super.beforePreLayout(recycler, lm, state);
+                    }
+
+                    @Override
+                    void afterPreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        mLayoutItemCount = 8;
+                        super.afterPreLayout(recycler, layoutManager, state);
+                    }
+                };
+
+                mLayoutManager.expectLayouts(2);
+                mTestAdapter.deleteAndNotify(2, 1);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                // This LM implements predictive animations properly by requesting target view
+                // in pre-layout.
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(itemAnimator.mMoveVHs.contains(target));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    public void testDontReuseHiddenViewOnInvalidate() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                mTestAdapter.dispatchDataSetChanged();
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                assertFalse(mRecyclerView.getItemAnimator().isRunning());
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    public void testDontReuseOnTypeChange() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                target.mBoundItem.mType += 2;
+                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+                mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1);
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+
+                assertTrue(itemAnimator.mChangeOldVHs.contains(target));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView));
+                assertFalse(recycledVHs.contains(target));
+                waitForAnimations(5);
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    interface ReuseTestCallback {
+
+        void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable;
     }
 
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    protected RecyclerView.ItemAnimator createItemAnimator() {
+        return new LoggingItemAnimator();
     }
 
-    RecyclerView setupBasic(int itemCount) throws Throwable {
-        return setupBasic(itemCount, 0, itemCount);
-    }
-
-    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount)
-            throws Throwable {
-        return setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null);
-    }
-
-    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount,
-            TestAdapter testAdapter)
-            throws Throwable {
-        final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
-        recyclerView.setHasFixedSize(true);
-        if (testAdapter == null) {
-            mTestAdapter = new TestAdapter(itemCount);
-        } else {
-            mTestAdapter = testAdapter;
-        }
-        recyclerView.setAdapter(mTestAdapter);
-        mLayoutManager = new AnimationLayoutManager();
-        recyclerView.setLayoutManager(mLayoutManager);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = firstLayoutStartIndex;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = firstLayoutItemCount;
-
-        mLayoutManager.expectLayouts(1);
-        recyclerView.expectDraw(1);
-        setRecyclerView(recyclerView);
+    public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable {
+        TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public void onViewRecycled(TestViewHolder holder) {
+                super.onViewRecycled(holder);
+                recycledVHs.add(holder);
+            }
+        };
+        setupBasic(10, 0, 10, adapter);
+        mRecyclerView.setItemViewCacheSize(0);
+        TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9);
+        mRecyclerView.getItemAnimator().setAddDuration(1000);
+        mRecyclerView.getItemAnimator().setRemoveDuration(1000);
+        mRecyclerView.getItemAnimator().setChangeDuration(1000);
+        mRecyclerView.getItemAnimator().setMoveDuration(1000);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
+        mLayoutManager.expectLayouts(2);
+        adapter.deleteAndNotify(2, 1);
         mLayoutManager.waitForLayout(2);
-        recyclerView.waitForDraw(1);
-        mLayoutManager.mOnLayoutCallbacks.reset();
-        getInstrumentation().waitForIdleSync();
-        assertEquals("extra layouts should not happen", 1, mLayoutManager.getTotalLayoutCount());
-        assertEquals("all expected children should be laid out", firstLayoutItemCount,
-                mLayoutManager.getChildCount());
-        return recyclerView;
+        // test sanity, make sure target is hidden now
+        assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView));
+        callback.postSetup(recycledVHs, target);
+        // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN
+        // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED
+        // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION
+
     }
 
     public void testDetachBeforeAnimations() throws Throwable {
@@ -133,7 +381,7 @@
                 mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
                     @Override
                     public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                                               RecyclerView.State state) {
+                            RecyclerView.State state) {
                         if (view == targetChild[0]) {
                             outRect.set(10, 20, 30, 40);
                         } else {
@@ -287,7 +535,6 @@
         mLayoutManager.waitForLayout(2);
 
 
-
     }
 
     public void testAddRemoveSamePass() throws Throwable {
@@ -379,7 +626,11 @@
         assertTrue("added-removed view should be recycled", found);
     }
 
-    public void testChangeAnimations()  throws Throwable {
+    public void testTmpRemoveMe() throws Throwable {
+        changeAnimTest(false, false, true, false);
+    }
+
+    public void testChangeAnimations() throws Throwable {
         final boolean[] booleans = {true, false};
         for (boolean supportsChange : booleans) {
             for (boolean changeType : booleans) {
@@ -392,15 +643,16 @@
             }
         }
     }
+
     public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType,
-            final boolean hasStableIds, final boolean deleteSomeItems)  throws Throwable {
+            final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable {
         final int changedIndex = 3;
         final int defaultType = 1;
         final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType);
         final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim +
                 ", change view type:" + changeType +
                 ", has stable ids:" + hasStableIds +
-                ", force predictive:" + deleteSomeItems;
+                ", delete some items:" + deleteSomeItems;
         TestAdapter testAdapter = new TestAdapter(10) {
             @Override
             public int getItemViewType(int position) {
@@ -428,7 +680,8 @@
         };
         testAdapter.setHasStableIds(hasStableIds);
         setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
-        mRecyclerView.getItemAnimator().setSupportsChangeAnimations(supportsChangeAnim);
+        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
+                supportsChangeAnim);
 
         final RecyclerView.ViewHolder toBeChangedVH =
                 mRecyclerView.findViewHolderForLayoutPosition(changedIndex);
@@ -439,13 +692,8 @@
                     RecyclerView.State state) {
                 RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
                         changedIndex);
-                if (supportsChangeAnim) {
-                    assertTrue(logPrefix + " changed view holder should have correct flag"
-                            , vh.isChanged());
-                } else {
-                    assertFalse(logPrefix + " changed view holder should have correct flag"
-                            , vh.isChanged());
-                }
+                assertTrue(logPrefix + " changed view holder should have correct flag"
+                        , vh.isUpdated());
             }
 
             @Override
@@ -453,7 +701,6 @@
                     AnimationLayoutManager layoutManager, RecyclerView.State state) {
                 RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
                         changedIndex);
-                assertFalse(logPrefix + "VH should not be marked as changed", vh.isChanged());
                 if (supportsChangeAnim) {
                     assertNotSame(logPrefix + "a new VH should be given if change is supported",
                             toBeChangedVH, vh);
@@ -482,7 +729,7 @@
                 }
             });
         } else {
-            mTestAdapter.notifyItemChanged(3);
+            mTestAdapter.changeAndNotify(3, 1);
         }
 
         mLayoutManager.waitForLayout(2);
@@ -492,7 +739,7 @@
         if (list1.size() != list2.size()) {
             return false;
         }
-        for (int i= 0; i < list1.size(); i++) {
+        for (int i = 0; i < list1.size(); i++) {
             if (!list1.get(i).equals(list2.get(i))) {
                 return false;
             }
@@ -501,8 +748,8 @@
     }
 
     private void testChangeWithPayload(final boolean supportsChangeAnim,
-            Object[][] notifyPayloads,  Object[][] expectedPayloadsInOnBind)
-                    throws Throwable {
+            Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind)
+            throws Throwable {
         final List<Object> expectedPayloads = new ArrayList<Object>();
         final int changedIndex = 3;
         TestAdapter testAdapter = new TestAdapter(10) {
@@ -533,10 +780,11 @@
         };
         testAdapter.setHasStableIds(false);
         setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
-        mRecyclerView.getItemAnimator().setSupportsChangeAnimations(supportsChangeAnim);
+        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
+                supportsChangeAnim);
 
         int numTests = notifyPayloads.length;
-        for (int i= 0; i < numTests; i++) {
+        for (int i = 0; i < numTests; i++) {
             mLayoutManager.expectLayouts(1);
             expectedPayloads.clear();
             for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) {
@@ -552,45 +800,46 @@
                 }
             });
             mLayoutManager.waitForLayout(2);
+            checkForMainThreadException();
         }
     }
 
-    public void testCrossFadingChangeAnimationWithPayload()  throws Throwable {
+    public void testCrossFadingChangeAnimationWithPayload() throws Throwable {
         // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
         testChangeWithPayload(true,
                 new Object[][]{
-                    new Object[]{"abc"},
-                    new Object[]{"abc", null, "cdf"},
-                    new Object[]{"abc", null},
-                    new Object[]{null, "abc"},
-                    new Object[]{"abc", "cdf"}
+                        new Object[]{"abc"},
+                        new Object[]{"abc", null, "cdf"},
+                        new Object[]{"abc", null},
+                        new Object[]{null, "abc"},
+                        new Object[]{"abc", "cdf"}
                 },
                 new Object[][]{
-                    new Object[0],
-                    new Object[0],
-                    new Object[0],
-                    new Object[0],
-                    new Object[0]
+                        new Object[0],
+                        new Object[0],
+                        new Object[0],
+                        new Object[0],
+                        new Object[0]
                 });
     }
 
-    public void testNoChangeAnimationWithPayload()  throws Throwable {
+    public void testNoChangeAnimationWithPayload() throws Throwable {
         // for Change Animation disabled, payload should match the payloads unless
         // null payload is fired.
         testChangeWithPayload(false,
                 new Object[][]{
-                    new Object[]{"abc"},
-                    new Object[]{"abc", null, "cdf"},
-                    new Object[]{"abc", null},
-                    new Object[]{null, "abc"},
-                    new Object[]{"abc", "cdf"}
+                        new Object[]{"abc"},
+                        new Object[]{"abc", null, "cdf"},
+                        new Object[]{"abc", null},
+                        new Object[]{null, "abc"},
+                        new Object[]{"abc", "cdf"}
                 },
                 new Object[][]{
-                new Object[]{"abc"},
-                new Object[0],
-                new Object[0],
-                new Object[0],
-                new Object[]{"abc", "cdf"}
+                        new Object[]{"abc"},
+                        new Object[0],
+                        new Object[0],
+                        new Object[0],
+                        new Object[]{"abc", "cdf"}
                 });
     }
 
@@ -626,7 +875,7 @@
         });
 
         // now keep adding children to trigger more children being created etc.
-        for (int i = 0; i < 100; i ++) {
+        for (int i = 0; i < 100; i++) {
             adapter.addAndNotify(15, 1);
             Thread.sleep(50);
         }
@@ -674,19 +923,19 @@
         adapter.setHasStableIds(true);
         initialSet.addAll(adapter.mItems);
         positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() {
-            @Override
-            void onRun(TestAdapter testAdapter) throws Throwable {
-                Item item5 = adapter.mItems.get(5);
-                Item item6 = adapter.mItems.get(6);
-                item5.mAdapterIndex = 6;
-                item6.mAdapterIndex = 5;
-                adapter.mItems.remove(5);
-                adapter.mItems.add(6, item5);
-                adapter.dispatchDataSetChanged();
-                //hacky, we support only 1 layout pass
-                mLayoutManager.layoutLatch.countDown();
-            }
-        }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
+                    @Override
+                    void onRun(TestAdapter testAdapter) throws Throwable {
+                        Item item5 = adapter.mItems.get(5);
+                        Item item6 = adapter.mItems.get(6);
+                        item5.mAdapterIndex = 6;
+                        item6.mAdapterIndex = 5;
+                        adapter.mItems.remove(5);
+                        adapter.mItems.add(6, item5);
+                        adapter.dispatchDataSetChanged();
+                        //hacky, we support only 1 layout pass
+                        mLayoutManager.layoutLatch.countDown();
+                    }
+                }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
                 PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8),
                 PositionConstraint.scrap(9, -1, 9));
         // now mix items.
@@ -738,7 +987,7 @@
                     itemViewTypeQueries.contains(i));
             if (adapter.hasStableIds()) {
                 assertTrue("getItemId for existing item " + i
-                        + " should be called when adapter has stable ids",
+                                + " should be called when adapter has stable ids",
                         itemIdQueries.contains(i));
             }
         }
@@ -779,13 +1028,17 @@
         // try to trigger race conditions
         int targetItemCount = mTestAdapter.getItemCount();
         for (int i = 0; i < 100; i++) {
+            checkForMainThreadException();
             mTestAdapter.addAndNotify(0, 1);
+            checkForMainThreadException();
             mTestAdapter.addAndNotify(7, 1);
             targetItemCount += 2;
         }
+        checkForMainThreadException();
         // wait until main thread runnables are consumed
         while (targetItemCount != mTestAdapter.getItemCount()) {
             Thread.sleep(100);
+            checkForMainThreadException();
         }
         mLayoutManager.waitForLayout(2);
     }
@@ -990,10 +1243,6 @@
                 8, mRecyclerView.getChildCount());
     }
 
-    public TestRecyclerView getTestRecyclerView() {
-        return (TestRecyclerView) mRecyclerView;
-    }
-
     public void testRemoveScrapInvalidate() throws Throwable {
         setupBasic(10);
         TestRecyclerView testRecyclerView = getTestRecyclerView();
@@ -1035,11 +1284,14 @@
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                // [0,1,2,3,4]
-                // delete 1
-                mTestAdapter.notifyItemRangeRemoved(1, 1);
-                // delete 3
-                mTestAdapter.notifyItemRangeRemoved(2, 1);
+                try {
+                    // delete 1
+                    mTestAdapter.deleteAndNotify(1, 1);
+                    // delete 3
+                    mTestAdapter.deleteAndNotify(2, 1);
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
             }
         });
         mLayoutManager.waitForLayout(2);
@@ -1092,35 +1344,35 @@
 
     public void testAddDelete2() throws Throwable {
         positionStatesTest(5, 0, 5, new AdapterOps() {
-            // 0 1 2 3 4
-            // 0 1 2 a b 3 4
-            // 0 1 b 3 4
-            // pre: 0 1 2 3 4
-            // pre w/ adap: 0 1 2 b 3 4
-            @Override
-            void onRun(TestAdapter adapter) throws Throwable {
-                adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
-            }
-        }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
+                    // 0 1 2 3 4
+                    // 0 1 2 a b 3 4
+                    // 0 1 b 3 4
+                    // pre: 0 1 2 3 4
+                    // pre w/ adap: 0 1 2 b 3 4
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
+                    }
+                }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
                 PositionConstraint.scrap(3, 3, 3)
         );
     }
 
     public void testAddDelete1() throws Throwable {
         positionStatesTest(5, 0, 5, new AdapterOps() {
-            // 0 1 2 3 4
-            // 0 1 2 a b 3 4
-            // 0 2 a b 3 4
-            // 0 c d 2 a b 3 4
-            // 0 c d 2 a 4
-            // c d 2 a 4
-            // pre: 0 1 2 3 4
-            @Override
-            void onRun(TestAdapter adapter) throws Throwable {
-                adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
-                        new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
-            }
-        }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
+                    // 0 1 2 3 4
+                    // 0 1 2 a b 3 4
+                    // 0 2 a b 3 4
+                    // 0 c d 2 a b 3 4
+                    // 0 c d 2 a 4
+                    // c d 2 a 4
+                    // pre: 0 1 2 3 4
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
+                                new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
+                    }
+                }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
                 PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1),
                 PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0),
                 PositionConstraint.adapter(1), PositionConstraint.adapter(3)
@@ -1129,12 +1381,12 @@
 
     public void testAddSameIndexTwice() throws Throwable {
         positionStatesTest(12, 2, 7, new AdapterOps() {
-            @Override
-            void onRun(TestAdapter adapter) throws Throwable {
-                adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
-                        new int[]{11, 1});
-            }
-        }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
+                                new int[]{11, 1});
+                    }
+                }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
                 PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7),
                 PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12),
                 PositionConstraint.scrap(8, 8, 13)
@@ -1143,12 +1395,12 @@
 
     public void testDeleteTwice() throws Throwable {
         positionStatesTest(12, 2, 7, new AdapterOps() {
-            @Override
-            void onRun(TestAdapter adapter) throws Throwable {
-                adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
-                        new int[]{0, 1});// delete item ids 0,2,9,1
-            }
-        }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
+                                new int[]{0, 1});// delete item ids 0,2,9,1
+                    }
+                }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
                 PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2),
                 PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5),
                 PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7)
@@ -1160,10 +1412,11 @@
             int firstLayoutItemCount, AdapterOps adapterChanges,
             final PositionConstraint... constraints) throws Throwable {
         positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null,
-                adapterChanges,  constraints);
+                adapterChanges, constraints);
     }
+
     public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
-            int firstLayoutItemCount,TestAdapter adapter, AdapterOps adapterChanges,
+            int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges,
             final PositionConstraint... constraints) throws Throwable {
         setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter);
         mLayoutManager.expectLayouts(2);
@@ -1180,10 +1433,15 @@
                 }
                 Map<Integer, CollectPositionResult> positions
                         = collectPositions(lm.mRecyclerView, recycler, state, ids);
+                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
+                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
+                    positionLog.append(entry.getKey()).append(":").append(entry.getValue())
+                            .append("\n");
+                }
                 for (PositionConstraint constraint : constraints) {
                     if (constraint.mPreLayoutPos != -1) {
                         constraint.validate(state, positions.get(constraint.mPreLayoutPos),
-                                lm.getLog());
+                                lm.getLog() + positionLog);
                     }
                 }
             }
@@ -1199,10 +1457,15 @@
                 }
                 Map<Integer, CollectPositionResult> positions
                         = collectPositions(lm.mRecyclerView, recycler, state, ids);
+                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
+                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
+                    positionLog.append(entry.getKey()).append(":")
+                            .append(entry.getValue()).append("\n");
+                }
                 for (PositionConstraint constraint : constraints) {
                     if (constraint.mPostLayoutPos >= 0) {
                         constraint.validate(state, positions.get(constraint.mPostLayoutPos),
-                                lm.getLog());
+                                lm.getLog() + positionLog);
                     }
                 }
             }
@@ -1218,7 +1481,8 @@
     public void testAddThenRecycleRemovedView() throws Throwable {
         setupBasic(10);
         final AtomicInteger step = new AtomicInteger(0);
-        final List<RecyclerView.ViewHolder> animateRemoveList = new ArrayList<RecyclerView.ViewHolder>();
+        final List<RecyclerView.ViewHolder> animateRemoveList
+                = new ArrayList<RecyclerView.ViewHolder>();
         DefaultItemAnimator animator = new DefaultItemAnimator() {
             @Override
             public boolean animateRemove(RecyclerView.ViewHolder holder) {
@@ -1264,530 +1528,4 @@
         assertTrue("since LM force recycled a view, animate disappearance should not be called",
                 animateRemoveList.isEmpty());
     }
-
-    class AnimationLayoutManager extends TestLayoutManager {
-
-        private int mTotalLayoutCount = 0;
-        private String log;
-
-        OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() {
-        };
-
-
-
-        @Override
-        public boolean supportsPredictiveItemAnimations() {
-            return true;
-        }
-
-        public String getLog() {
-            return log;
-        }
-
-        private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) {
-            StringBuilder builder = new StringBuilder();
-            builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done);
-            builder.append("\nViewHolders:\n");
-            for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) {
-                builder.append(vh).append("\n");
-            }
-            builder.append("scrap:\n");
-            for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
-                builder.append(vh).append("\n");
-            }
-
-            if (state.isPreLayout() && !done) {
-                log = "\n" + builder.toString();
-            } else {
-                log += "\n" + builder.toString();
-            }
-            return log;
-        }
-
-        @Override
-        public void expectLayouts(int count) {
-            super.expectLayouts(count);
-            mOnLayoutCallbacks.mLayoutCount = 0;
-        }
-
-        public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) {
-            mOnLayoutCallbacks = onLayoutCallbacks;
-        }
-
-        @Override
-        public final void onLayoutChildren(RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            try {
-                mTotalLayoutCount++;
-                prepareLog(recycler, state, false);
-                if (state.isPreLayout()) {
-                    validateOldPositions(recycler, state);
-                } else {
-                    validateClearedOldPositions(recycler, state);
-                }
-                mOnLayoutCallbacks.onLayoutChildren(recycler, this, state);
-                prepareLog(recycler, state, true);
-            } finally {
-                layoutLatch.countDown();
-            }
-        }
-
-        private void validateClearedOldPositions(RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            if (getTestRecyclerView() == null) {
-                return;
-            }
-            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
-                assertEquals("there should NOT be an old position in post layout",
-                        RecyclerView.NO_POSITION, viewHolder.mOldPosition);
-                assertEquals("there should NOT be a pre layout position in post layout",
-                        RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition);
-            }
-        }
-
-        private void validateOldPositions(RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            if (getTestRecyclerView() == null) {
-                return;
-            }
-            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
-                if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) {
-                    assertTrue("there should be an old position in pre-layout",
-                            viewHolder.mOldPosition != RecyclerView.NO_POSITION);
-                }
-            }
-        }
-
-        public int getTotalLayoutCount() {
-            return mTotalLayoutCount;
-        }
-
-        @Override
-        public boolean canScrollVertically() {
-            return true;
-        }
-
-        @Override
-        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            mOnLayoutCallbacks.onScroll(dy, recycler, state);
-            return super.scrollVerticallyBy(dy, recycler, state);
-        }
-
-        public void onPostDispatchLayout() {
-            mOnLayoutCallbacks.postDispatchLayout();
-        }
-
-        @Override
-        public void waitForLayout(long timeout, TimeUnit timeUnit) throws Throwable {
-            super.waitForLayout(timeout, timeUnit);
-            checkForMainThreadException();
-        }
-    }
-
-    abstract class OnLayoutCallbacks {
-
-        int mLayoutMin = Integer.MIN_VALUE;
-
-        int mLayoutItemCount = Integer.MAX_VALUE;
-
-        int expectedPreLayoutItemCount = -1;
-
-        int expectedPostLayoutItemCount = -1;
-
-        int mDeletedViewCount;
-
-        int mLayoutCount = 0;
-
-        void setExpectedItemCounts(int preLayout, int postLayout) {
-            expectedPreLayoutItemCount = preLayout;
-            expectedPostLayoutItemCount = postLayout;
-        }
-
-        void reset() {
-            mLayoutMin = Integer.MIN_VALUE;
-            mLayoutItemCount = Integer.MAX_VALUE;
-            expectedPreLayoutItemCount = -1;
-            expectedPostLayoutItemCount = -1;
-            mLayoutCount = 0;
-        }
-
-        void beforePreLayout(RecyclerView.Recycler recycler,
-                AnimationLayoutManager lm, RecyclerView.State state) {
-            mDeletedViewCount = 0;
-            for (int i = 0; i < lm.getChildCount(); i++) {
-                View v = lm.getChildAt(i);
-                if (lm.getLp(v).isItemRemoved()) {
-                    mDeletedViewCount++;
-                }
-            }
-        }
-
-        void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
-                RecyclerView.State state) {
-            if (DEBUG) {
-                Log.d(TAG, "item count " + state.getItemCount());
-            }
-            lm.detachAndScrapAttachedViews(recycler);
-            final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin;
-            final int count = mLayoutItemCount
-                    == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount;
-            lm.layoutRange(recycler, start, start + count);
-            assertEquals("correct # of children should be laid out",
-                    count, lm.getChildCount());
-            lm.assertVisibleItemPositions();
-        }
-
-        private void assertNoPreLayoutPosition(RecyclerView.Recycler recycler) {
-            for (RecyclerView.ViewHolder vh : recycler.mAttachedScrap) {
-                assertPreLayoutPosition(vh);
-            }
-        }
-
-        private void assertNoPreLayoutPosition(RecyclerView.LayoutManager lm) {
-            for (int i = 0; i < lm.getChildCount(); i ++) {
-                final RecyclerView.ViewHolder vh = mRecyclerView
-                        .getChildViewHolder(lm.getChildAt(i));
-                assertPreLayoutPosition(vh);
-            }
-        }
-
-        private void assertPreLayoutPosition(RecyclerView.ViewHolder vh) {
-            assertEquals("in post layout, there should not be a view holder w/ a pre "
-                    + "layout position", RecyclerView.NO_POSITION, vh.mPreLayoutPosition);
-            assertEquals("in post layout, there should not be a view holder w/ an old "
-                    + "layout position", RecyclerView.NO_POSITION, vh.mOldPosition);
-        }
-
-        void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
-                RecyclerView.State state) {
-
-            if (state.isPreLayout()) {
-                if (expectedPreLayoutItemCount != -1) {
-                    assertEquals("on pre layout, state should return abstracted adapter size",
-                            expectedPreLayoutItemCount, state.getItemCount());
-                }
-                beforePreLayout(recycler, lm, state);
-            } else {
-                if (expectedPostLayoutItemCount != -1) {
-                    assertEquals("on post layout, state should return real adapter size",
-                            expectedPostLayoutItemCount, state.getItemCount());
-                }
-                beforePostLayout(recycler, lm, state);
-            }
-            if (!state.isPreLayout()) {
-                assertNoPreLayoutPosition(recycler);
-            }
-            doLayout(recycler, lm, state);
-            if (state.isPreLayout()) {
-                afterPreLayout(recycler, lm, state);
-            } else {
-                afterPostLayout(recycler, lm, state);
-                assertNoPreLayoutPosition(lm);
-            }
-            mLayoutCount++;
-        }
-
-        void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
-                RecyclerView.State state) {
-        }
-
-        void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
-                RecyclerView.State state) {
-        }
-
-        void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
-                RecyclerView.State state) {
-        }
-
-        void postDispatchLayout() {
-        }
-
-        public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
-
-        }
-    }
-
-    class TestRecyclerView extends RecyclerView {
-
-        CountDownLatch drawLatch;
-
-        public TestRecyclerView(Context context) {
-            super(context);
-        }
-
-        public TestRecyclerView(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
-            super(context, attrs, defStyle);
-        }
-
-        @Override
-        void initAdapterManager() {
-            super.initAdapterManager();
-            mAdapterHelper.mOnItemProcessedCallback = new Runnable() {
-                @Override
-                public void run() {
-                    validatePostUpdateOp();
-                }
-            };
-        }
-
-        @Override
-        boolean isAccessibilityEnabled() {
-            return true;
-        }
-
-        public void expectDraw(int count) {
-            drawLatch = new CountDownLatch(count);
-        }
-
-        public void waitForDraw(long timeout) throws Throwable {
-            drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS);
-            assertEquals("all expected draws should happen at the expected time frame",
-                    0, drawLatch.getCount());
-        }
-
-        List<ViewHolder> collectViewHolders() {
-            List<ViewHolder> holders = new ArrayList<ViewHolder>();
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                ViewHolder holder = getChildViewHolderInt(getChildAt(i));
-                if (holder != null) {
-                    holders.add(holder);
-                }
-            }
-            return holders;
-        }
-
-
-        private void validateViewHolderPositions() {
-            final Set<Integer> existingOffsets = new HashSet<Integer>();
-            int childCount = getChildCount();
-            StringBuilder log = new StringBuilder();
-            for (int i = 0; i < childCount; i++) {
-                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
-                TestViewHolder tvh = (TestViewHolder) vh;
-                log.append(tvh.mBoundItem).append(vh)
-                        .append(" hidden:")
-                        .append(mChildHelper.mHiddenViews.contains(vh.itemView))
-                        .append("\n");
-            }
-            for (int i = 0; i < childCount; i++) {
-                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
-                if (vh.isInvalid()) {
-                    continue;
-                }
-                if (vh.getLayoutPosition() < 0) {
-                    LayoutManager lm = getLayoutManager();
-                    for (int j = 0; j < lm.getChildCount(); j ++) {
-                        assertNotSame("removed view holder should not be in LM's child list",
-                                vh.itemView, lm.getChildAt(j));
-                    }
-                } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) {
-                    if (!existingOffsets.add(vh.getLayoutPosition())) {
-                        throw new IllegalStateException("view holder position conflict for "
-                                + "existing views " + vh + "\n" + log);
-                    }
-                }
-            }
-        }
-
-        void validatePostUpdateOp() {
-            try {
-                validateViewHolderPositions();
-                if (super.mState.isPreLayout()) {
-                    validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager());
-                }
-                validateAdapterPosition((AnimationLayoutManager) getLayoutManager());
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-        }
-
-
-
-        private void validateAdapterPosition(AnimationLayoutManager lm) {
-            for (ViewHolder vh : collectViewHolders()) {
-                if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) {
-                    assertEquals("adapter position calculations should match view holder "
-                            + "pre layout:" + mState.isPreLayout()
-                            + " positions\n" + vh + "\n" + lm.getLog(),
-                            mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition);
-                }
-            }
-        }
-
-        // ensures pre layout positions are continuous block. This is not necessarily a case
-        // but valid in test RV
-        private void validatePreLayoutSequence(AnimationLayoutManager lm) {
-            Set<Integer> preLayoutPositions = new HashSet<Integer>();
-            for (ViewHolder vh : collectViewHolders()) {
-                assertTrue("pre layout positions should be distinct " + lm.getLog(),
-                        preLayoutPositions.add(vh.mPreLayoutPosition));
-            }
-            int minPos = Integer.MAX_VALUE;
-            for (Integer pos : preLayoutPositions) {
-                if (pos < minPos) {
-                    minPos = pos;
-                }
-            }
-            for (int i = 1; i < preLayoutPositions.size(); i++) {
-                assertNotNull("next position should exist " + lm.getLog(),
-                        preLayoutPositions.contains(minPos + i));
-            }
-        }
-
-        @Override
-        protected void dispatchDraw(Canvas canvas) {
-            super.dispatchDraw(canvas);
-            if (drawLatch != null) {
-                drawLatch.countDown();
-            }
-        }
-
-        @Override
-        void dispatchLayout() {
-            try {
-                super.dispatchLayout();
-                if (getLayoutManager() instanceof AnimationLayoutManager) {
-                    ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout();
-                }
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-
-        }
-
-
-    }
-
-    abstract class AdapterOps {
-
-        final public void run(TestAdapter adapter) throws Throwable {
-            onRun(adapter);
-        }
-
-        abstract void onRun(TestAdapter testAdapter) throws Throwable;
-    }
-
-    static class CollectPositionResult {
-
-        // true if found in scrap
-        public RecyclerView.ViewHolder scrapResult;
-
-        public RecyclerView.ViewHolder adapterResult;
-
-        static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) {
-            CollectPositionResult cpr = new CollectPositionResult();
-            cpr.scrapResult = viewHolder;
-            return cpr;
-        }
-
-        static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) {
-            CollectPositionResult cpr = new CollectPositionResult();
-            cpr.adapterResult = viewHolder;
-            return cpr;
-        }
-    }
-
-    static class PositionConstraint {
-
-        public static enum Type {
-            scrap,
-            adapter,
-            adapterScrap /*first pass adapter, second pass scrap*/
-        }
-
-        Type mType;
-
-        int mOldPos; // if VH
-
-        int mPreLayoutPos;
-
-        int mPostLayoutPos;
-
-        int mValidateCount = 0;
-
-        public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) {
-            PositionConstraint constraint = new PositionConstraint();
-            constraint.mType = Type.scrap;
-            constraint.mOldPos = oldPos;
-            constraint.mPreLayoutPos = preLayoutPos;
-            constraint.mPostLayoutPos = postLayoutPos;
-            return constraint;
-        }
-
-        public static PositionConstraint adapterScrap(int preLayoutPos, int position) {
-            PositionConstraint constraint = new PositionConstraint();
-            constraint.mType = Type.adapterScrap;
-            constraint.mOldPos = RecyclerView.NO_POSITION;
-            constraint.mPreLayoutPos = preLayoutPos;
-            constraint.mPostLayoutPos = position;// adapter pos does not change
-            return constraint;
-        }
-
-        public static PositionConstraint adapter(int position) {
-            PositionConstraint constraint = new PositionConstraint();
-            constraint.mType = Type.adapter;
-            constraint.mPreLayoutPos = RecyclerView.NO_POSITION;
-            constraint.mOldPos = RecyclerView.NO_POSITION;
-            constraint.mPostLayoutPos = position;// adapter pos does not change
-            return constraint;
-        }
-
-        public void assertValidate() {
-            int expectedValidate = 0;
-            if (mPreLayoutPos >= 0) {
-                expectedValidate ++;
-            }
-            if (mPostLayoutPos >= 0) {
-                expectedValidate ++;
-            }
-            assertEquals("should run all validates", expectedValidate, mValidateCount);
-        }
-
-        @Override
-        public String toString() {
-            return "Cons{" +
-                    "t=" + mType.name() +
-                    ", old=" + mOldPos +
-                    ", pre=" + mPreLayoutPos +
-                    ", post=" + mPostLayoutPos +
-                    '}';
-        }
-
-        public void validate(RecyclerView.State state, CollectPositionResult result, String log) {
-            mValidateCount ++;
-            assertNotNull(this + ": result should not be null\n" + log, result);
-            RecyclerView.ViewHolder viewHolder;
-            if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) {
-                assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult);
-                viewHolder = result.scrapResult;
-            } else {
-                assertNotNull(this + ": result should come from adapter\n"  + log,
-                        result.adapterResult);
-                assertEquals(this + ": old position should be none when it came from adapter\n" + log,
-                        RecyclerView.NO_POSITION, result.adapterResult.getOldPosition());
-                viewHolder = result.adapterResult;
-            }
-            if (state.isPreLayout()) {
-                assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos,
-                        viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition :
-                        viewHolder.mPreLayoutPosition);
-                assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos,
-                        viewHolder.getLayoutPosition());
-                if (mType == Type.scrap) {
-                    assertEquals(this + ": old position should match\n" + log, mOldPos,
-                            result.scrapResult.getOldPosition());
-                }
-            } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult
-                    .isRemoved()) {
-                assertEquals(this + ": post-layout position should match\n" + log + "\n\n"
-                        + viewHolder, mPostLayoutPos, viewHolder.getLayoutPosition());
-            }
-        }
-    }
 }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index 366758a..6fb9592 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -28,7 +28,6 @@
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.RecyclerView;
 import android.test.TouchUtils;
 import android.util.Log;
 import android.view.Gravity;
@@ -62,7 +61,7 @@
     private static final int FLAG_VERTICAL = 1 << 1;
     private static final int FLAG_FLING = 1 << 2;
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final String TAG = "RecyclerViewLayoutTest";
 
@@ -174,9 +173,9 @@
     }
 
     @Test
-    public void testFocusSearchFailFrozen() throws Throwable {
+    public void  testFocusSearchFailFrozen() throws Throwable {
         RecyclerView recyclerView = new RecyclerView(getActivity());
-
+        final CountDownLatch focusLatch = new CountDownLatch(1);
         final AtomicInteger focusSearchCalled = new AtomicInteger(0);
         TestLayoutManager tlm = new TestLayoutManager() {
             @Override
@@ -196,9 +195,10 @@
             }
 
             @Override
-            public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
+            public View onFocusSearchFailed(View focused, int direction,
+                    RecyclerView.Recycler recycler, RecyclerView.State state) {
                 focusSearchCalled.addAndGet(1);
+                focusLatch.countDown();
                 return null;
             }
         };
@@ -217,14 +217,13 @@
             }
         });
         assertTrue(c.hasFocus());
-
         freezeLayout(true);
         sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
         assertEquals("onFocusSearchFailed should not be called when layout is frozen",
                 0, focusSearchCalled.get());
-
         freezeLayout(false);
         sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
         assertEquals(1, focusSearchCalled.get());
     }
 
@@ -1214,6 +1213,7 @@
         TestLayoutManager lm = new TestLayoutManager() {
             @Override
             public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                ViewInfoStore infoStore = mRecyclerView.mViewInfoStore;
                 if (test.get()) {
                     try {
                         detachAndScrapAttachedViews(recycler);
@@ -1225,25 +1225,26 @@
                                         recycler);
                             }
                         }
-                        if (state.mOldChangedHolders != null) {
-                            for (int i = state.mOldChangedHolders.size() - 1; i >= 0; i--) {
+                        if (infoStore.mOldChangedHolders != null) {
+                            for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) {
                                 if (useRecycler) {
                                     recycler.recycleView(
-                                            state.mOldChangedHolders.valueAt(i).itemView);
+                                            infoStore.mOldChangedHolders.valueAt(i).itemView);
                                 } else {
                                     removeAndRecycleView(
-                                            state.mOldChangedHolders.valueAt(i).itemView, recycler);
+                                            infoStore.mOldChangedHolders.valueAt(i).itemView,
+                                            recycler);
                                 }
                             }
                         }
                         assertEquals("no scrap should be left over", 0, recycler.getScrapCount());
                         assertEquals("pre layout map should be empty", 0,
-                                state.mPreLayoutHolderMap.size());
+                                InfoStoreTrojan.sizeOfPreLayout(infoStore));
                         assertEquals("post layout map should be empty", 0,
-                                state.mPostLayoutHolderMap.size());
-                        if (state.mOldChangedHolders != null) {
+                                InfoStoreTrojan.sizeOfPostLayout(infoStore));
+                        if (infoStore.mOldChangedHolders != null) {
                             assertEquals("post old change map should be empty", 0,
-                                    state.mOldChangedHolders.size());
+                                    infoStore.mOldChangedHolders.size());
                         }
                     } catch (Throwable t) {
                         postExceptionToInstrumentation(t);
@@ -1258,7 +1259,7 @@
         RecyclerView recyclerView = new RecyclerView(getActivity());
         recyclerView.setAdapter(testAdapter);
         recyclerView.setLayoutManager(lm);
-        recyclerView.getItemAnimator().setSupportsChangeAnimations(true);
+        ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true);
         lm.expectLayouts(1);
         setRecyclerView(recyclerView);
         lm.waitForLayout(2);
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v7/recyclerview/tests/src/android/support/v7/widget/ViewInfoStoreTest.java
similarity index 60%
copy from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
copy to v7/recyclerview/tests/src/android/support/v7/widget/ViewInfoStoreTest.java
index 8eea38d..4c78e3d 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/ViewInfoStoreTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -13,18 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.support.v7.widget;
 
-package android.support.v7.internal.widget;
+public class ViewInfoStoreTest {
 
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-
-/**
- * @hide
- */
-public class TintInfo {
-    public ColorStateList mTintList;
-    public PorterDuff.Mode mTintMode;
-    public boolean mHasTintMode;
-    public boolean mHasTintList;
 }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
index dfa2974..c2fac6e 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -17,7 +17,6 @@
 package android.support.v7.widget.helper;
 
 import android.app.Instrumentation;
-import android.os.Debug;
 import android.os.SystemClock;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java
index f722314..6565e6f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java
@@ -20,7 +20,9 @@
 import android.support.v7.recyclerview.test.CustomLayoutManager;
 import android.support.v7.recyclerview.test.R;
 import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
 import android.test.ActivityInstrumentationTestCase2;
 import android.widget.LinearLayout;
 
@@ -40,6 +42,14 @@
         });
     }
 
+    public void testSavedStateAccess() throws ClassNotFoundException {
+        // this class should be accessible outside RecyclerView package
+        assertNotNull(RecyclerView.SavedState.class);
+        assertNotNull(LinearLayoutManager.SavedState.class);
+        assertNotNull(GridLayoutManager.SavedState.class);
+        assertNotNull(StaggeredGridLayoutManager.SavedState.class);
+    }
+
     public void testInflation() throws Throwable {
         setContentView(R.layout.inflation_test);
         getInstrumentation().waitForIdleSync();
diff --git a/v8/renderscript/api/23.txt b/v8/renderscript/api/23.0.0.txt
similarity index 100%
rename from v8/renderscript/api/23.txt
rename to v8/renderscript/api/23.0.0.txt
diff --git a/v8/renderscript/api/23.txt b/v8/renderscript/api/23.1.0.txt
similarity index 100%
copy from v8/renderscript/api/23.txt
copy to v8/renderscript/api/23.1.0.txt