Merge "Fix BottomNavigationView example to use AAPT1 style." into nyc-support-25.1-dev
am: 2c0862c41c

Change-Id: I407d92ce766631aa56b1cda5924759ba9be97242
diff --git a/api/current.txt b/api/current.txt
index 6709b97..6e529c8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2040,6 +2040,7 @@
     method public void setFadingEnabled(boolean);
     method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
     method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
     method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
     method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
@@ -2124,6 +2125,7 @@
     method public void setFadingEnabled(boolean);
     method public void setHostCallback(android.support.v17.leanback.media.PlaybackGlueHost.HostCallback);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.BaseOnItemViewSelectedListener);
     method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
     method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
     method public void setPlaybackRow(android.support.v17.leanback.widget.Row);
@@ -5264,6 +5266,10 @@
     method public static int setAlphaComponent(int, int);
   }
 
+  public final class PaintCompat {
+    method public static boolean hasGlyph(android.graphics.Paint, java.lang.String);
+  }
+
 }
 
 package android.support.v4.graphics.drawable {
diff --git a/build.gradle b/build.gradle
index ff9f772..8feee6d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -24,7 +24,7 @@
     }
     dependencies {
         // Keep gradle plugin version in sync with ub_supportlib-master manifest.
-        classpath 'com.android.tools.build:gradle:2.2.1'
+        classpath 'com.android.tools.build:gradle:2.2.4'
     }
 }
 
@@ -40,8 +40,8 @@
     doclava project(':doclava')
 }
 
-ext.supportVersion = '25.2.0'
-ext.extraVersion = 43
+ext.supportVersion = '25.2.0-SNAPSHOT'
+ext.extraVersion = 41
 ext.supportRepoOut = ''
 ext.buildNumber = Integer.toString(ext.extraVersion)
 
@@ -163,6 +163,7 @@
     Files.write(xml, new File(project.ext.distDir, 'repo-extras.xml'), Charsets.UTF_8)
 }
 createArchive.dependsOn createXml
+createXml.dependsOn createRepository
 
 task(createSourceProp) << {
     def sourceProp =
@@ -488,6 +489,14 @@
             }
         }
     }
+
+    // Update the version meta-data in each Manifest
+    project.afterEvaluate { p ->
+        if (p.hasProperty('android')) {
+            p.android.defaultConfig.manifestPlaceholders =
+                    ["support-version": rootProject.ext.supportVersion]
+        }
+    }
 }
 
 project.gradle.buildFinished { buildResult ->
diff --git a/compat/Android.mk b/compat/Android.mk
index ba5b958..97916ae 100644
--- a/compat/Android.mk
+++ b/compat/Android.mk
@@ -45,6 +45,7 @@
     $(call all-java-files-under,java) \
     $(call all-Iaidl-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
diff --git a/compat/AndroidManifest-make.xml b/compat/AndroidManifest-make.xml
new file mode 100644
index 0000000..b2bd5bb
--- /dev/null
+++ b/compat/AndroidManifest-make.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.compat">
+    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.compat"/>
+    <application />
+</manifest>
diff --git a/compat/AndroidManifest.xml b/compat/AndroidManifest.xml
index b2bd5bb..55ddcff 100644
--- a/compat/AndroidManifest.xml
+++ b/compat/AndroidManifest.xml
@@ -17,5 +17,6 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.compat">
     <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.compat"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java b/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
new file mode 100644
index 0000000..c51f175
--- /dev/null
+++ b/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.graphics;
+
+import android.graphics.Paint;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+
+@RequiresApi(23)
+class PaintCompatApi23 {
+    static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
+        return paint.hasGlyph(string);
+    }
+}
diff --git a/compat/build.gradle b/compat/build.gradle
index 5722998..e87db0e 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -15,9 +15,6 @@
     testCompile 'junit:junit:4.12'
 }
 
-sourceCompatibility = JavaVersion.VERSION_1_7
-targetCompatibility = JavaVersion.VERSION_1_7
-
 android {
     compileSdkVersion project.ext.currentSdk
 
@@ -58,11 +55,7 @@
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
-
-    testOptions {
-        unitTests.returnDefaultValues = true
         compileSdkVersion project.ext.currentSdk
-    }
 }
 
 android.libraryVariants.all { variant ->
@@ -73,22 +66,6 @@
     }
     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
@@ -96,7 +73,6 @@
         exclude('android/service/media/**')
     }
 
-    artifacts.add('archives', javadocJarTask);
     artifacts.add('archives', sourcesJarTask);
 }
 
diff --git a/compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java b/compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java
new file mode 100644
index 0000000..0d1076f
--- /dev/null
+++ b/compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 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.graphics;
+
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.v4.util.Pair;
+
+@RequiresApi(9)
+class PaintCompatGingerbread {
+    // U+DFFFD which is very end of unassigned plane.
+    private static final String TOFU_STRING = "\uDB3F\uDFFD";
+
+    private static final ThreadLocal<Pair<Rect, Rect>> sRectThreadLocal = new ThreadLocal<>();
+
+    static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
+        final int length = string.length();
+
+        if (length == 1 && Character.isWhitespace(string.charAt(0))) {
+            // measureText + getTextBounds skips whitespace so we need to special case it here
+            return true;
+        }
+
+        final float missingGlyphWidth = paint.measureText(TOFU_STRING);
+        final float width = paint.measureText(string);
+
+        if (width == 0f) {
+            // If the string width is 0, it can't be rendered
+            return false;
+        }
+
+        if (string.codePointCount(0, string.length()) > 1) {
+            // Heuristic to detect fallback glyphs for ligatures like flags and ZWJ sequences
+            // Return false if string is rendered too widely
+            if (width > 2 * missingGlyphWidth) {
+                return false;
+            }
+
+            // Heuristic to detect fallback glyphs for ligatures like flags and ZWJ sequences (2).
+            // If width is greater than or equal to the sum of width of each code point, it is very
+            // likely that the system is using fallback fonts to draw {@code string} in two or more
+            // glyphs instead of a single ligature glyph. (hasGlyph returns false in this case.)
+            // False detections are possible (the ligature glyph may happen to have the same width
+            // as the sum width), but there are no good way to avoid them.
+            // NOTE: This heuristic does not work with proportional glyphs.
+            // NOTE: This heuristic does not work when a ZWJ sequence is partially combined.
+            // E.g. If system has a glyph for "A ZWJ B" and not for "A ZWJ B ZWJ C", this heuristic
+            // returns true for "A ZWJ B ZWJ C".
+            float sumWidth = 0;
+            int i = 0;
+            while (i < length) {
+                int charCount = Character.charCount(string.codePointAt(i));
+                sumWidth += paint.measureText(string, i, i + charCount);
+                i += charCount;
+            }
+            if (width >= sumWidth) {
+                return false;
+            }
+        }
+
+        if (width != missingGlyphWidth) {
+            // If the widths are different then its not tofu
+            return true;
+        }
+
+        // If the widths are the same, lets check the bounds. The chance of them being
+        // different chars with the same bounds is extremely small
+        final Pair<Rect, Rect> rects = obtainEmptyRects();
+        paint.getTextBounds(TOFU_STRING, 0, TOFU_STRING.length(), rects.first);
+        paint.getTextBounds(string, 0, length, rects.second);
+        return !rects.first.equals(rects.second);
+    }
+
+    private static Pair<Rect, Rect> obtainEmptyRects() {
+        Pair<Rect, Rect> rects = sRectThreadLocal.get();
+        if (rects == null) {
+            rects = new Pair(new Rect(), new Rect());
+            sRectThreadLocal.set(rects);
+        } else {
+            rects.first.setEmpty();
+            rects.second.setEmpty();
+        }
+        return rects;
+    }
+}
diff --git a/compat/java/android/support/v4/app/NotificationCompat.java b/compat/java/android/support/v4/app/NotificationCompat.java
index 492d0fd..5d08191 100644
--- a/compat/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/java/android/support/v4/app/NotificationCompat.java
@@ -17,6 +17,7 @@
 package android.support.v4.app;
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.app.Activity;
 import android.app.Notification;
@@ -30,6 +31,7 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.support.annotation.ColorInt;
+import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
 import android.support.v4.os.BuildCompat;
@@ -37,6 +39,7 @@
 import android.view.Gravity;
 import android.widget.RemoteViews;
 
+import java.lang.annotation.Retention;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -390,6 +393,10 @@
     @ColorInt
     public static final int COLOR_DEFAULT = Color.TRANSPARENT;
 
+    /** @hide */
+    @Retention(SOURCE)
+    @IntDef({VISIBILITY_PUBLIC, VISIBILITY_PRIVATE, VISIBILITY_SECRET})
+    public @interface NotificationVisibility {}
     /**
      * Notification visibility: Show this notification in its entirety on all lockscreens.
      *
@@ -1665,7 +1672,7 @@
          *                   {@link Notification#VISIBILITY_PUBLIC}, or
          *                   {@link Notification#VISIBILITY_SECRET}.
          */
-        public Builder setVisibility(int visibility) {
+        public Builder setVisibility(@NotificationVisibility int visibility) {
             mVisibility = visibility;
             return this;
         }
@@ -2147,7 +2154,7 @@
         public static MessagingStyle extractMessagingStyleFromNotification(Notification notif) {
             MessagingStyle style;
             Bundle extras = IMPL.getExtras(notif);
-            if (!extras.containsKey(EXTRA_SELF_DISPLAY_NAME)) {
+            if (extras != null && !extras.containsKey(EXTRA_SELF_DISPLAY_NAME)) {
                 style = null;
             } else {
                 try {
diff --git a/compat/java/android/support/v4/graphics/PaintCompat.java b/compat/java/android/support/v4/graphics/PaintCompat.java
new file mode 100644
index 0000000..66599f7
--- /dev/null
+++ b/compat/java/android/support/v4/graphics/PaintCompat.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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.graphics;
+
+import android.graphics.Paint;
+import android.os.Build;
+import android.support.annotation.NonNull;
+
+/**
+ * Helper for accessing features in {@link Paint} in a backwards compatible fashion.
+ */
+public final class PaintCompat {
+
+    /**
+     * Determine whether the typeface set on the paint has a glyph supporting the
+     * string in a backwards compatible way.
+     *
+     * @param paint the paint instance to check
+     * @param string the string to test whether there is glyph support
+     * @return true if the typeface set on the given paint has a glyph for the string
+     */
+    public static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
+        if (Build.VERSION.SDK_INT >= 23) {
+            return PaintCompatApi23.hasGlyph(paint, string);
+        }
+        return PaintCompatGingerbread.hasGlyph(paint, string);
+    }
+
+    private PaintCompat() {}
+}
diff --git a/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java b/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
index fd873c7..c50e5f0 100644
--- a/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
+++ b/compat/jellybean/android/support/v4/app/NotificationCompatJellybean.java
@@ -298,21 +298,24 @@
             RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory) {
         synchronized (sActionsLock) {
             try {
-                Object actionObject = getActionObjectsLocked(notif)[actionIndex];
-                Bundle actionExtras = null;
-                Bundle extras = getExtras(notif);
-                if (extras != null) {
-                    SparseArray<Bundle> actionExtrasMap = extras.getSparseParcelableArray(
-                            EXTRA_ACTION_EXTRAS);
-                    if (actionExtrasMap != null) {
-                        actionExtras = actionExtrasMap.get(actionIndex);
+                Object[] actionObjects = getActionObjectsLocked(notif);
+                if (actionObjects != null) {
+                    Object actionObject = actionObjects[actionIndex];
+                    Bundle actionExtras = null;
+                    Bundle extras = getExtras(notif);
+                    if (extras != null) {
+                        SparseArray<Bundle> actionExtrasMap = extras.getSparseParcelableArray(
+                                EXTRA_ACTION_EXTRAS);
+                        if (actionExtrasMap != null) {
+                            actionExtras = actionExtrasMap.get(actionIndex);
+                        }
                     }
+                    return readAction(factory, remoteInputFactory,
+                            sActionIconField.getInt(actionObject),
+                            (CharSequence) sActionTitleField.get(actionObject),
+                            (PendingIntent) sActionIntentField.get(actionObject),
+                            actionExtras);
                 }
-                return readAction(factory, remoteInputFactory,
-                        sActionIconField.getInt(actionObject),
-                        (CharSequence) sActionTitleField.get(actionObject),
-                        (PendingIntent) sActionIntentField.get(actionObject),
-                        actionExtras);
             } catch (IllegalAccessException e) {
                 Log.e(TAG, "Unable to access notification actions", e);
                 sActionsAccessFailed = true;
diff --git a/compat/tests/java/android/support/v4/graphics/PaintCompatHasGlyphTest.java b/compat/tests/java/android/support/v4/graphics/PaintCompatHasGlyphTest.java
new file mode 100644
index 0000000..202d30f
--- /dev/null
+++ b/compat/tests/java/android/support/v4/graphics/PaintCompatHasGlyphTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.graphics;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Paint;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@SmallTest
+public class PaintCompatHasGlyphTest {
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {"B", true},
+                {"\uDB3F\uDFFD", false},
+                {"☺", true},
+                {"Hello", false},
+                {"\u0020", true},  // white space
+                {"\t\t\t", false},  // more white space
+        });
+    }
+
+    private final String mTestString;
+    private final boolean mExpectedResult;
+
+    public PaintCompatHasGlyphTest(String testString, boolean expectedResult) {
+        mTestString = testString;
+        mExpectedResult = expectedResult;
+    }
+
+    @Test
+    public void testHasGlyph() {
+        assertEquals(mExpectedResult, PaintCompat.hasGlyph(new Paint(), mTestString));
+    }
+}
diff --git a/core-ui/Android.mk b/core-ui/Android.mk
index bdad9f9..eb9acca 100644
--- a/core-ui/Android.mk
+++ b/core-ui/Android.mk
@@ -33,6 +33,7 @@
     $(call all-java-files-under,api21) \
     $(call all-java-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/core-ui/AndroidManifest-make.xml b/core-ui/AndroidManifest-make.xml
new file mode 100644
index 0000000..9bcc44e
--- /dev/null
+++ b/core-ui/AndroidManifest-make.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.coreui">
+    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreui"/>
+    <application />
+</manifest>
diff --git a/core-ui/AndroidManifest.xml b/core-ui/AndroidManifest.xml
index 9bcc44e..5357112 100644
--- a/core-ui/AndroidManifest.xml
+++ b/core-ui/AndroidManifest.xml
@@ -17,5 +17,6 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreui">
     <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreui"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 89796ea..0b94a96 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -16,9 +16,6 @@
     testCompile 'junit:junit:4.12'
 }
 
-sourceCompatibility = JavaVersion.VERSION_1_7
-targetCompatibility = JavaVersion.VERSION_1_7
-
 android {
     compileSdkVersion project.ext.currentSdk
 
@@ -54,7 +51,6 @@
 
     testOptions {
         unitTests.returnDefaultValues = true
-        compileSdkVersion project.ext.currentSdk
     }
 }
 
@@ -66,22 +62,6 @@
     }
     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
@@ -89,7 +69,6 @@
         exclude('android/service/media/**')
     }
 
-    artifacts.add('archives', javadocJarTask);
     artifacts.add('archives', sourcesJarTask);
 }
 
diff --git a/core-utils/Android.mk b/core-utils/Android.mk
index d3f113e..a65a2cd 100644
--- a/core-utils/Android.mk
+++ b/core-utils/Android.mk
@@ -37,6 +37,7 @@
     $(call all-java-files-under,api24) \
     $(call all-java-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/core-utils/AndroidManifest-make.xml b/core-utils/AndroidManifest-make.xml
new file mode 100644
index 0000000..586a28e
--- /dev/null
+++ b/core-utils/AndroidManifest-make.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.coreutils">
+    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreutils"/>
+    <application />
+</manifest>
diff --git a/core-utils/AndroidManifest.xml b/core-utils/AndroidManifest.xml
index 586a28e..03ff3b4 100644
--- a/core-utils/AndroidManifest.xml
+++ b/core-utils/AndroidManifest.xml
@@ -17,5 +17,6 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreutils">
     <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.coreutils"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index 750cf49..d40781d 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -48,11 +48,6 @@
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
-
-    testOptions {
-        unitTests.returnDefaultValues = true
-        compileSdkVersion project.ext.currentSdk
-    }
 }
 
 android.libraryVariants.all { variant ->
@@ -63,22 +58,6 @@
     }
     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
@@ -86,7 +65,6 @@
         exclude('android/service/media/**')
     }
 
-    artifacts.add('archives', javadocJarTask);
     artifacts.add('archives', sourcesJarTask);
 }
 
diff --git a/customtabs/Android.mk b/customtabs/Android.mk
index cfd9971..e6f6ead 100644
--- a/customtabs/Android.mk
+++ b/customtabs/Android.mk
@@ -31,6 +31,7 @@
     $(call all-java-files-under,src) \
     $(call all-Iaidl-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations \
     android-support-compat
diff --git a/customtabs/AndroidManifest-make.xml b/customtabs/AndroidManifest-make.xml
new file mode 100644
index 0000000..212fab9
--- /dev/null
+++ b/customtabs/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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"
+          package="android.support.customtabs">
+    <uses-sdk android:minSdkVersion="15"/>
+    <application />
+</manifest>
diff --git a/customtabs/AndroidManifest.xml b/customtabs/AndroidManifest.xml
index 212fab9..19a1d54 100644
--- a/customtabs/AndroidManifest.xml
+++ b/customtabs/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.customtabs">
     <uses-sdk android:minSdkVersion="15"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index a409dba..e427d1e 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'customtabs'
 
 dependencies {
@@ -48,27 +47,10 @@
     }
     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);
 }
diff --git a/design/Android.mk b/design/Android.mk
index b3bc846..2e634eb 100644
--- a/design/Android.mk
+++ b/design/Android.mk
@@ -38,6 +38,7 @@
     $(call all-java-files-under,lollipop) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-transition \
     android-support-v7-appcompat \
diff --git a/design/AndroidManifest-make.xml b/design/AndroidManifest-make.xml
new file mode 100644
index 0000000..d51186d
--- /dev/null
+++ b/design/AndroidManifest-make.xml
@@ -0,0 +1,22 @@
+<?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.design">
+    <uses-sdk android:minSdkVersion="9"
+              tools:overrideLibrary="android.support.transition"/>
+    <application />
+</manifest>
diff --git a/design/AndroidManifest.xml b/design/AndroidManifest.xml
index d51186d..2d5fe0b 100644
--- a/design/AndroidManifest.xml
+++ b/design/AndroidManifest.xml
@@ -18,5 +18,6 @@
           package="android.support.design">
     <uses-sdk android:minSdkVersion="9"
               tools:overrideLibrary="android.support.transition"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/design/build.gradle b/design/build.gradle
index abd99c0..37e6625 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -83,28 +83,11 @@
     }
     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);
 }
 
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
index 44db0ea..ad05e76 100644
--- a/design/src/android/support/design/internal/BottomNavigationItemView.java
+++ b/design/src/android/support/design/internal/BottomNavigationItemView.java
@@ -122,6 +122,7 @@
     public void setTitle(CharSequence title) {
         mSmallLabel.setText(title);
         mLargeLabel.setText(title);
+        setContentDescription(title);
     }
 
     @Override
diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java
index 82d983e..92a9a84 100644
--- a/design/src/android/support/design/internal/BottomNavigationMenuView.java
+++ b/design/src/android/support/design/internal/BottomNavigationMenuView.java
@@ -31,6 +31,7 @@
 import android.support.v7.view.menu.MenuItemImpl;
 import android.support.v7.view.menu.MenuView;
 import android.util.AttributeSet;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -51,7 +52,8 @@
     private boolean mShiftingMode = true;
 
     private BottomNavigationItemView[] mButtons;
-    private int mActiveButton = 0;
+    private int mSelectedItemId = 0;
+    private int mSelectedItemPosition = 0;
     private ColorStateList mItemIconTint;
     private ColorStateList mItemTextColor;
     private int mItemBackgroundRes;
@@ -114,7 +116,7 @@
             final int inactiveWidth = Math.min(inactiveMaxAvailable, mInactiveItemMaxWidth);
             int extra = width - activeWidth - inactiveWidth * inactiveCount;
             for (int i = 0; i < count; i++) {
-                mTempChildWidths[i] = (i == mActiveButton) ? activeWidth : inactiveWidth;
+                mTempChildWidths[i] = (i == mSelectedItemPosition) ? activeWidth : inactiveWidth;
                 if (extra > 0) {
                     mTempChildWidths[i]++;
                     extra--;
@@ -275,8 +277,8 @@
             child.setOnClickListener(mOnClickListener);
             addView(child);
         }
-        mActiveButton = Math.min(mMenu.size() - 1, mActiveButton);
-        mMenu.getItem(mActiveButton).setChecked(true);
+        mSelectedItemPosition = Math.min(mMenu.size() - 1, mSelectedItemPosition);
+        mMenu.getItem(mSelectedItemPosition).setChecked(true);
     }
 
     public void updateMenuView() {
@@ -288,22 +290,26 @@
         }
         for (int i = 0; i < menuSize; i++) {
             mPresenter.setUpdateSuspended(true);
-            if (mMenu.getItem(i).isChecked()) {
-                mActiveButton = i;
+            MenuItem item = mMenu.getItem(i);
+            if (item.isChecked()) {
+                mSelectedItemId = item.getItemId();
+                mSelectedItemPosition = i;
             }
-            mButtons[i].initialize((MenuItemImpl) mMenu.getItem(i), 0);
+            mButtons[i].initialize((MenuItemImpl) item, 0);
             mPresenter.setUpdateSuspended(false);
         }
     }
 
     private void activateNewButton(int newButton) {
-        if (mActiveButton == newButton) return;
+        if (mSelectedItemPosition == newButton) {
+            return;
+        }
 
         mAnimationHelper.beginDelayedTransition(this);
 
         mMenu.getItem(newButton).setChecked(true);
 
-        mActiveButton = newButton;
+        mSelectedItemPosition = newButton;
     }
 
     private BottomNavigationItemView getNewItem() {
@@ -313,4 +319,21 @@
         }
         return item;
     }
+
+    int getSelectedItemId() {
+        return mSelectedItemId;
+    }
+
+    void tryRestoreSelectedItemId(int itemId) {
+        final int size = mMenu.size();
+        for (int i = 0; i < size; i++) {
+            MenuItem item = mMenu.getItem(i);
+            if (itemId == item.getItemId()) {
+                mSelectedItemId = itemId;
+                mSelectedItemPosition = i;
+                item.setChecked(true);
+                break;
+            }
+        }
+    }
 }
diff --git a/design/src/android/support/design/internal/BottomNavigationPresenter.java b/design/src/android/support/design/internal/BottomNavigationPresenter.java
index 832e936..1343a4b 100644
--- a/design/src/android/support/design/internal/BottomNavigationPresenter.java
+++ b/design/src/android/support/design/internal/BottomNavigationPresenter.java
@@ -19,7 +19,9 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.content.Context;
+import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
 import android.support.v7.view.menu.MenuBuilder;
 import android.support.v7.view.menu.MenuItemImpl;
@@ -36,6 +38,7 @@
     private MenuBuilder mMenu;
     private BottomNavigationMenuView mMenuView;
     private boolean mUpdateSuspended = false;
+    private int mId;
 
     public void setBottomNavigationMenuView(BottomNavigationMenuView menuView) {
         mMenuView = menuView;
@@ -88,20 +91,62 @@
         return false;
     }
 
+    public void setId(int id) {
+        mId = id;
+    }
+
     @Override
     public int getId() {
-        return -1;
+        return mId;
     }
 
     @Override
     public Parcelable onSaveInstanceState() {
-        return null;
+        SavedState savedState = new SavedState();
+        savedState.selectedItemId = mMenuView.getSelectedItemId();
+        return savedState;
     }
 
     @Override
-    public void onRestoreInstanceState(Parcelable state) {}
+    public void onRestoreInstanceState(Parcelable state) {
+        if (state instanceof SavedState) {
+            mMenuView.tryRestoreSelectedItemId(((SavedState) state).selectedItemId);
+        }
+    }
 
     public void setUpdateSuspended(boolean updateSuspended) {
         mUpdateSuspended = updateSuspended;
     }
+
+    static class SavedState implements Parcelable {
+        int selectedItemId;
+
+        SavedState() {}
+
+        SavedState(Parcel in) {
+            selectedItemId = in.readInt();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel out, int flags) {
+            out.writeInt(selectedItemId);
+        }
+
+        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
 }
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
index 4c7ef0a..ff41db8 100644
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ b/design/src/android/support/design/widget/AppBarLayout.java
@@ -111,6 +111,7 @@
     static final int PENDING_ACTION_EXPANDED = 0x1;
     static final int PENDING_ACTION_COLLAPSED = 0x2;
     static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
+    static final int PENDING_ACTION_FORCE = 0x8;
 
     /**
      * Interface definition for a callback to be invoked when an {@link AppBarLayout}'s vertical
@@ -172,7 +173,7 @@
                 0, R.style.Widget_Design_AppBarLayout);
         ViewCompat.setBackground(this, a.getDrawable(R.styleable.AppBarLayout_android_background));
         if (a.hasValue(R.styleable.AppBarLayout_expanded)) {
-            setExpanded(a.getBoolean(R.styleable.AppBarLayout_expanded, false));
+            setExpanded(a.getBoolean(R.styleable.AppBarLayout_expanded, false), false, false);
         }
         if (Build.VERSION.SDK_INT >= 21 && a.hasValue(R.styleable.AppBarLayout_elevation)) {
             ViewUtilsLollipop.setDefaultAppBarLayoutStateListAnimator(
@@ -299,8 +300,13 @@
      * @attr ref android.support.design.R.styleable#AppBarLayout_expanded
      */
     public void setExpanded(boolean expanded, boolean animate) {
+        setExpanded(expanded, animate, true);
+    }
+
+    private void setExpanded(boolean expanded, boolean animate, boolean force) {
         mPendingAction = (expanded ? PENDING_ACTION_EXPANDED : PENDING_ACTION_COLLAPSED)
-                | (animate ? PENDING_ACTION_ANIMATE_ENABLED : 0);
+                | (animate ? PENDING_ACTION_ANIMATE_ENABLED : 0)
+                | (force ? PENDING_ACTION_FORCE : 0);
         requestLayout();
     }
 
@@ -408,8 +414,8 @@
                     // Only enter by the amount of the collapsed height
                     range += childHeight - ViewCompat.getMinimumHeight(child);
                 } else {
-                    // Else use the full height
-                    range += childHeight;
+                    // Else use the full height (minus the top inset)
+                    range += childHeight - getTopInset();
                 }
             } else if (range > 0) {
                 // If we've hit an non-quick return scrollable view, and we've already hit a
@@ -1048,8 +1054,21 @@
                 int layoutDirection) {
             boolean handled = super.onLayoutChild(parent, abl, layoutDirection);
 
+            // The priority for for actions here is (first which is true wins):
+            // 1. forced pending actions
+            // 2. offsets for restorations
+            // 3. non-forced pending actions
             final int pendingAction = abl.getPendingAction();
-            if (pendingAction != PENDING_ACTION_NONE) {
+            if (mOffsetToChildIndexOnLayout >= 0 && (pendingAction & PENDING_ACTION_FORCE) == 0) {
+                View child = abl.getChildAt(mOffsetToChildIndexOnLayout);
+                int offset = -child.getBottom();
+                if (mOffsetToChildIndexOnLayoutIsMinHeight) {
+                    offset += ViewCompat.getMinimumHeight(child) + abl.getTopInset();
+                } else {
+                    offset += Math.round(child.getHeight() * mOffsetToChildIndexOnLayoutPerc);
+                }
+                setHeaderTopBottomOffset(parent, abl, offset);
+            } else if (pendingAction != PENDING_ACTION_NONE) {
                 final boolean animate = (pendingAction & PENDING_ACTION_ANIMATE_ENABLED) != 0;
                 if ((pendingAction & PENDING_ACTION_COLLAPSED) != 0) {
                     final int offset = -abl.getUpNestedPreScrollRange();
@@ -1065,15 +1084,6 @@
                         setHeaderTopBottomOffset(parent, abl, 0);
                     }
                 }
-            } else if (mOffsetToChildIndexOnLayout >= 0) {
-                View child = abl.getChildAt(mOffsetToChildIndexOnLayout);
-                int offset = -child.getBottom();
-                if (mOffsetToChildIndexOnLayoutIsMinHeight) {
-                    offset += ViewCompat.getMinimumHeight(child);
-                } else {
-                    offset += Math.round(child.getHeight() * mOffsetToChildIndexOnLayoutPerc);
-                }
-                setTopAndBottomOffset(offset);
             }
 
             // Finally reset any pending states
@@ -1085,6 +1095,11 @@
             setTopAndBottomOffset(
                     MathUtils.constrain(getTopAndBottomOffset(), -abl.getTotalScrollRange(), 0));
 
+            // Update the AppBarLayout's drawable state for any elevation changes.
+            // This is needed so that the elevation is set in the first layout, so that
+            // we don't get a visual elevation jump pre-N (due to the draw dispatch skip)
+            updateAppBarLayoutDrawableState(parent, abl, getTopAndBottomOffset(), 0, true);
+
             // Make sure we dispatch the offset update
             abl.dispatchOffsetUpdates(getTopAndBottomOffset());
 
@@ -1161,7 +1176,7 @@
 
                     // Update the AppBarLayout's drawable state (for any elevation changes)
                     updateAppBarLayoutDrawableState(coordinatorLayout, appBarLayout, newOffset,
-                            newOffset < curOffset ? -1 : 1);
+                            newOffset < curOffset ? -1 : 1, false);
                 }
             } else {
                 // Reset the offset delta
@@ -1224,7 +1239,8 @@
         }
 
         private void updateAppBarLayoutDrawableState(final CoordinatorLayout parent,
-                final AppBarLayout layout, final int offset, final int direction) {
+                final AppBarLayout layout, final int offset, final int direction,
+                final boolean forceJump) {
             final View child = getAppBarChildOnOffset(layout, offset);
             if (child != null) {
                 final AppBarLayout.LayoutParams childLp = (LayoutParams) child.getLayoutParams();
@@ -1248,8 +1264,8 @@
 
                 final boolean changed = layout.setCollapsedState(collapsed);
 
-                if (changed && Build.VERSION.SDK_INT >= 11
-                        && shouldJumpElevationState(parent, layout)) {
+                if (Build.VERSION.SDK_INT >= 11 && (forceJump
+                        || (changed && shouldJumpElevationState(parent, layout)))) {
                     // If the collapsed state changed, we may need to
                     // jump to the current state if we have an overlapping view
                     layout.jumpDrawablesToCurrentState();
diff --git a/design/src/android/support/design/widget/BaseTransientBottomBar.java b/design/src/android/support/design/widget/BaseTransientBottomBar.java
index 864417d..9035f82 100644
--- a/design/src/android/support/design/widget/BaseTransientBottomBar.java
+++ b/design/src/android/support/design/widget/BaseTransientBottomBar.java
@@ -28,7 +28,6 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.IntRange;
 import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.design.R;
 import android.support.v4.view.ViewCompat;
@@ -418,12 +417,13 @@
                         switch (state) {
                             case SwipeDismissBehavior.STATE_DRAGGING:
                             case SwipeDismissBehavior.STATE_SETTLING:
-                                // If the view is being dragged or settling, cancel the timeout
-                                SnackbarManager.getInstance().cancelTimeout(mManagerCallback);
+                                // If the view is being dragged or settling, pause the timeout
+                                SnackbarManager.getInstance().pauseTimeout(mManagerCallback);
                                 break;
                             case SwipeDismissBehavior.STATE_IDLE:
                                 // If the view has been released and is idle, restore the timeout
-                                SnackbarManager.getInstance().restoreTimeout(mManagerCallback);
+                                SnackbarManager.getInstance()
+                                        .restoreTimeoutIfPaused(mManagerCallback);
                                 break;
                         }
                     }
@@ -688,20 +688,20 @@
         @Override
         public boolean onInterceptTouchEvent(CoordinatorLayout parent, SnackbarBaseLayout child,
                 MotionEvent event) {
-            // We want to make sure that we disable any Snackbar timeouts if the user is
-            // currently touching the Snackbar. We restore the timeout when complete
-            if (parent.isPointInChildBounds(child, (int) event.getX(), (int) event.getY())) {
-                switch (event.getActionMasked()) {
-                    case MotionEvent.ACTION_DOWN:
-                        SnackbarManager.getInstance().cancelTimeout(mManagerCallback);
-                        break;
-                    case MotionEvent.ACTION_UP:
-                    case MotionEvent.ACTION_CANCEL:
-                        SnackbarManager.getInstance().restoreTimeout(mManagerCallback);
-                        break;
-                }
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    // We want to make sure that we disable any Snackbar timeouts if the user is
+                    // currently touching the Snackbar. We restore the timeout when complete
+                    if (parent.isPointInChildBounds(child, (int) event.getX(),
+                            (int) event.getY())) {
+                        SnackbarManager.getInstance().pauseTimeout(mManagerCallback);
+                    }
+                    break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    SnackbarManager.getInstance().restoreTimeoutIfPaused(mManagerCallback);
+                    break;
             }
-
             return super.onInterceptTouchEvent(parent, child, event);
         }
     }
diff --git a/design/src/android/support/design/widget/BottomNavigationView.java b/design/src/android/support/design/widget/BottomNavigationView.java
index 3544d81..317ed3f 100644
--- a/design/src/android/support/design/widget/BottomNavigationView.java
+++ b/design/src/android/support/design/widget/BottomNavigationView.java
@@ -19,6 +19,9 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
@@ -27,6 +30,9 @@
 import android.support.design.internal.BottomNavigationMenuView;
 import android.support.design.internal.BottomNavigationPresenter;
 import android.support.v4.content.ContextCompat;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
+import android.support.v4.view.AbsSavedState;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.content.res.AppCompatResources;
 import android.support.v7.view.SupportMenuInflater;
@@ -91,6 +97,8 @@
     private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
     private static final int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled};
 
+    private static final int MENU_PRESENTER_ID = 1;
+
     private final MenuBuilder mMenu;
     private final BottomNavigationMenuView mMenuView;
     private final BottomNavigationPresenter mPresenter = new BottomNavigationPresenter();
@@ -121,6 +129,7 @@
         mMenuView.setLayoutParams(params);
 
         mPresenter.setBottomNavigationMenuView(mMenuView);
+        mPresenter.setId(MENU_PRESENTER_ID);
         mMenuView.setPresenter(mPresenter);
         mMenu.addMenuPresenter(mPresenter);
         mPresenter.initForMenu(getContext(), mMenu);
@@ -344,4 +353,60 @@
                 defaultColor
         });
     }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState savedState = new SavedState(superState);
+        savedState.menuPresenterState = new Bundle();
+        mMenu.savePresenterStates(savedState.menuPresenterState);
+        return savedState;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+        SavedState savedState = (SavedState) state;
+        super.onRestoreInstanceState(savedState.getSuperState());
+        mMenu.restorePresenterStates(savedState.menuPresenterState);
+    }
+
+    static class SavedState extends AbsSavedState {
+        Bundle menuPresenterState;
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        public SavedState(Parcel source, ClassLoader loader) {
+            super(source, loader);
+            readFromParcel(source, loader);
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeBundle(menuPresenterState);
+        }
+
+        private void readFromParcel(Parcel in, ClassLoader loader) {
+            menuPresenterState = in.readBundle(loader);
+        }
+
+        public static final 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];
+                    }
+                });
+    }
 }
diff --git a/design/src/android/support/design/widget/BottomSheetDialog.java b/design/src/android/support/design/widget/BottomSheetDialog.java
index de48937..c5fccb0 100644
--- a/design/src/android/support/design/widget/BottomSheetDialog.java
+++ b/design/src/android/support/design/widget/BottomSheetDialog.java
@@ -97,6 +97,14 @@
     }
 
     @Override
+    protected void onStart() {
+        super.onStart();
+        if (mBehavior != null) {
+            mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
+        }
+    }
+
+    @Override
     public void setCanceledOnTouchOutside(boolean cancel) {
         super.setCanceledOnTouchOutside(cancel);
         if (cancel && !mCancelable) {
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index bac67f9..e0ec883 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -1171,11 +1171,18 @@
     }
 
     /**
-     * Return the given gravity value or the default if the passed value is NO_GRAVITY.
-     * This should be used for children that are not anchored to another view or a keyline.
+     * Return the given gravity value, but if either or both of the axes doesn't have any gravity
+     * specified, the default value (start or top) is specified. This should be used for children
+     * that are not anchored to another view or a keyline.
      */
     private static int resolveGravity(int gravity) {
-        return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
+        if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
+            gravity |= GravityCompat.START;
+        }
+        if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
+            gravity |= Gravity.TOP;
+        }
+        return gravity;
     }
 
     /**
@@ -1293,7 +1300,7 @@
                 offsetChildByInset(child, inset, layoutDirection);
             }
 
-            if (type == EVENT_PRE_DRAW) {
+            if (type != EVENT_VIEW_REMOVED) {
                 // Did it change? if not continue
                 getLastChildRect(child, lastDrawRect);
                 if (lastDrawRect.equals(drawRect)) {
@@ -2560,8 +2567,10 @@
 
         /**
          * A {@link Gravity} value describing how this child view should lay out.
-         * If an {@link #setAnchorId(int) anchor} is also specified, the gravity describes
-         * how this child view should be positioned relative to its anchored position.
+         * If either or both of the axes are not specified, they are treated by CoordinatorLayout
+         * as {@link Gravity#TOP} or {@link GravityCompat#START}. If an
+         * {@link #setAnchorId(int) anchor} is also specified, the gravity describes how this child
+         * view should be positioned relative to its anchored position.
          */
         public int gravity = Gravity.NO_GRAVITY;
 
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index a096a3d..bd5ffba 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -133,6 +133,11 @@
     public static Snackbar make(@NonNull View view, @NonNull CharSequence text,
             @Duration int duration) {
         final ViewGroup parent = findSuitableParent(view);
+        if (parent == null) {
+            throw new IllegalArgumentException("No suitable parent found from the given view. "
+                    + "Please provide a valid view.");
+        }
+
         final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
         final SnackbarContentLayout content =
                 (SnackbarContentLayout) inflater.inflate(
@@ -324,6 +329,25 @@
         public SnackbarLayout(Context context, AttributeSet attrs) {
             super(context, attrs);
         }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            // Work around our backwards-compatible refactoring of Snackbar and inner content
+            // being inflated against snackbar's parent (instead of against the snackbar itself).
+            // Every child that is width=MATCH_PARENT is remeasured again and given the full width
+            // minus the paddings.
+            int childCount = getChildCount();
+            int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                if (child.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT) {
+                    child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY),
+                            MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
+                                    MeasureSpec.EXACTLY));
+                }
+            }
+        }
     }
 }
 
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
index b391a3a..43892d3 100644
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ b/design/src/android/support/design/widget/SnackbarManager.java
@@ -137,17 +137,19 @@
         }
     }
 
-    public void cancelTimeout(Callback callback) {
+    public void pauseTimeout(Callback callback) {
         synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback)) {
+            if (isCurrentSnackbarLocked(callback) && !mCurrentSnackbar.paused) {
+                mCurrentSnackbar.paused = true;
                 mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
             }
         }
     }
 
-    public void restoreTimeout(Callback callback) {
+    public void restoreTimeoutIfPaused(Callback callback) {
         synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback)) {
+            if (isCurrentSnackbarLocked(callback) && mCurrentSnackbar.paused) {
+                mCurrentSnackbar.paused = false;
                 scheduleTimeoutLocked(mCurrentSnackbar);
             }
         }
@@ -168,6 +170,7 @@
     private static class SnackbarRecord {
         final WeakReference<Callback> callback;
         int duration;
+        boolean paused;
 
         SnackbarRecord(int duration, Callback callback) {
             this.callback = new WeakReference<>(callback);
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 22f4546..10da563 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -201,8 +201,6 @@
         mCollapsingTextHelper.setPositionInterpolator(new AccelerateInterpolator());
         mCollapsingTextHelper.setCollapsedTextGravity(Gravity.TOP | GravityCompat.START);
 
-        mHintExpanded = mCollapsingTextHelper.getExpansionFraction() == 1f;
-
         final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
                 R.styleable.TextInputLayout, defStyleAttr, R.style.Widget_Design_TextInputLayout);
         mHintEnabled = a.getBoolean(R.styleable.TextInputLayout_hintEnabled, true);
@@ -380,8 +378,8 @@
 
         updatePasswordToggleView();
 
-        // Update the label visibility with no animation
-        updateLabelState(false);
+        // Update the label visibility with no animation, but force a state change
+        updateLabelState(false, true);
     }
 
     private void updateInputLayoutMargins() {
@@ -408,6 +406,10 @@
     }
 
     void updateLabelState(boolean animate) {
+        updateLabelState(animate, false);
+    }
+
+    void updateLabelState(final boolean animate, final boolean force) {
         final boolean isEnabled = isEnabled();
         final boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
         final boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
@@ -427,12 +429,12 @@
 
         if (hasText || (isEnabled() && (isFocused || isErrorShowing))) {
             // We should be showing the label so do so if it isn't already
-            if (mHintExpanded) {
+            if (force || mHintExpanded) {
                 collapseHint(animate);
             }
         } else {
             // We should not be showing the label so hide it
-            if (!mHintExpanded) {
+            if (force || !mHintExpanded) {
                 expandHint(animate);
             }
         }
diff --git a/design/tests/AndroidManifest.xml b/design/tests/AndroidManifest.xml
index 29d46e0..886540d 100755
--- a/design/tests/AndroidManifest.xml
+++ b/design/tests/AndroidManifest.xml
@@ -88,6 +88,10 @@
         <activity
                 android:name="android.support.v7.app.AppCompatActivity"/>
 
+        <activity
+            android:name="android.support.design.widget.AppBarLayoutCollapsePinTestActivity"
+            android:theme="@style/Theme.TranslucentStatus"/>
+
     </application>
 
     <instrumentation
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_pin_restore_test.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_pin_restore_test.xml
new file mode 100644
index 0000000..fbe031b
--- /dev/null
+++ b/design/tests/res/layout/design_appbar_toolbar_collapse_pin_restore_test.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<android.support.design.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/coordinator_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
+
+    <android.support.design.widget.AppBarLayout
+        android:id="@+id/app_bar"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/appbar_height"
+        android:fitsSystemWindows="true"
+        app:expanded="true">
+
+        <android.support.design.widget.CollapsingToolbarLayout
+            android:id="@+id/collapsing_app_bar"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            app:layout_scrollFlags="scroll|exitUntilCollapsed">
+
+            <android.support.v7.widget.Toolbar
+                android:id="@+id/toolbar"
+                android:layout_height="?attr/actionBarSize"
+                android:layout_width="match_parent"
+                app:layout_collapseMode="pin"/>
+
+        </android.support.design.widget.CollapsingToolbarLayout>
+
+    </android.support.design.widget.AppBarLayout>
+
+    <include layout="@layout/include_appbar_scrollview" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_scroll_enteralways.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_scroll_enteralways.xml
new file mode 100644
index 0000000..43a8d51
--- /dev/null
+++ b/design/tests/res/layout/design_appbar_toolbar_collapse_scroll_enteralways.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.design.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
+
+    <android.support.design.widget.AppBarLayout
+        android:id="@+id/app_bar"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/appbar_height"
+        android:fitsSystemWindows="true">
+
+        <android.support.design.widget.CollapsingToolbarLayout
+            android:id="@+id/collapsing_app_bar"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            app:layout_scrollFlags="scroll|enterAlways">
+
+            <android.support.v7.widget.Toolbar
+                android:id="@+id/toolbar"
+                android:layout_height="?attr/actionBarSize"
+                android:layout_width="match_parent"
+                app:layout_collapseMode="pin"/>
+
+        </android.support.design.widget.CollapsingToolbarLayout>
+
+    </android.support.design.widget.AppBarLayout>
+
+    <include layout="@layout/include_appbar_scrollview" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_text_input.xml b/design/tests/res/layout/design_text_input.xml
index f4bd1d1..4dba825 100644
--- a/design/tests/res/layout/design_text_input.xml
+++ b/design/tests/res/layout/design_text_input.xml
@@ -58,4 +58,18 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"/>
 
+    <android.support.design.widget.TextInputLayout
+        android:id="@+id/textinput_with_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <android.support.design.widget.TextInputEditText
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:imeOptions="flagNoExtractUi"
+            android:hint="@string/textinput_hint"
+            android:text="@string/snackbar_text"/>
+
+    </android.support.design.widget.TextInputLayout>
+
 </LinearLayout>
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/testutils/AppBarLayoutMatchers.java b/design/tests/src/android/support/design/testutils/AppBarLayoutMatchers.java
new file mode 100755
index 0000000..4d6fc63
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/AppBarLayoutMatchers.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.testutils;
+
+import android.support.design.widget.AppBarLayout;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+public class AppBarLayoutMatchers {
+
+    /**
+     * Returns a matcher that matches AppBarLayouts which are collapsed.
+     */
+    public static Matcher isCollapsed() {
+        return new TypeSafeMatcher<AppBarLayout>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("AppBarLayout is collapsed");
+            }
+
+            @Override
+            protected boolean matchesSafely(AppBarLayout item) {
+                return item.getBottom() == (item.getHeight() - item.getTotalScrollRange());
+            }
+        };
+    }
+
+}
diff --git a/design/tests/src/android/support/design/testutils/SwipeUtils.java b/design/tests/src/android/support/design/testutils/SwipeUtils.java
new file mode 100644
index 0000000..cf92883
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/SwipeUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.testutils;
+
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralSwipeAction;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swipe;
+import android.view.View;
+
+public class SwipeUtils {
+
+    public static GeneralSwipeAction swipeUp(final int swipeX,
+            final int swipeStartY, final int swipeAmountY) {
+        return new GeneralSwipeAction(
+                Swipe.SLOW,
+                new CoordinatesProvider() {
+                    @Override
+                    public float[] calculateCoordinates(View view) {
+                        return new float[] { swipeX, swipeStartY };
+                    }
+                },
+                new CoordinatesProvider() {
+                    @Override
+                    public float[] calculateCoordinates(View view) {
+                        return new float[] { swipeX, swipeStartY - swipeAmountY };
+                    }
+                },
+                Press.FINGER
+        );
+    }
+
+    public static GeneralSwipeAction swipeDown(final int swipeX,
+            final int swipeStartY, final int swipeAmountY) {
+        return new GeneralSwipeAction(
+                Swipe.SLOW,
+                new CoordinatesProvider() {
+                    @Override
+                    public float[] calculateCoordinates(View view) {
+                        return new float[] { swipeX, swipeStartY };
+                    }
+                },
+                new CoordinatesProvider() {
+                    @Override
+                    public float[] calculateCoordinates(View view) {
+                        return new float[] { swipeX, swipeStartY + swipeAmountY };
+                    }
+                },
+                Press.FINGER
+        );
+    }
+
+
+}
diff --git a/design/tests/src/android/support/design/testutils/TestUtils.java b/design/tests/src/android/support/design/testutils/TestUtils.java
index b9aae7a..2f9187d 100644
--- a/design/tests/src/android/support/design/testutils/TestUtils.java
+++ b/design/tests/src/android/support/design/testutils/TestUtils.java
@@ -16,7 +16,10 @@
 
 package android.support.design.testutils;
 
+import android.app.Activity;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -124,4 +127,20 @@
             }
         }
     }
+
+    /**
+     * Rotates the given Activity to either portrait or landscape, depending on the current
+     * orientation.
+     */
+    public static void rotateOrientation(@NonNull Activity activity) {
+        switch (activity.getResources().getConfiguration().orientation) {
+            case Configuration.ORIENTATION_PORTRAIT:
+                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+                break;
+            case Configuration.ORIENTATION_LANDSCAPE:
+            default:
+                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+                break;
+        }
+    }
 }
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java b/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
index 2f1f30d..9d13ce7 100644
--- a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
+++ b/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
@@ -22,6 +22,7 @@
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.design.widget.FloatingActionButton;
@@ -461,6 +462,24 @@
     }
 
     /**
+     * Returns a matcher that matches views which have a z-value greater than 0. Also matches if
+     * the platform we're running on does not support z-values.
+     */
+    public static Matcher<View> hasZ() {
+        return new TypeSafeMatcher<View>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("has a z value greater than 0");
+            }
+
+            @Override
+            public boolean matchesSafely(View view) {
+                return Build.VERSION.SDK_INT < 21 || ViewCompat.getZ(view) > 0f;
+            }
+        };
+    }
+
+    /**
      * Returns a matcher that matches TextViews with the specified typeface.
      */
     public static Matcher withTypeface(@NonNull final Typeface typeface) {
diff --git a/design/tests/src/android/support/design/widget/AppBarLayoutBaseTest.java b/design/tests/src/android/support/design/widget/AppBarLayoutBaseTest.java
index fc131a4..6fd4470 100644
--- a/design/tests/src/android/support/design/widget/AppBarLayoutBaseTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarLayoutBaseTest.java
@@ -17,6 +17,8 @@
 package android.support.design.widget;
 
 import static android.support.design.testutils.CollapsingToolbarLayoutActions.setContentScrimColor;
+import static android.support.design.testutils.SwipeUtils.swipeDown;
+import static android.support.design.testutils.SwipeUtils.swipeUp;
 import static android.support.design.testutils.TestUtilsActions.setText;
 import static android.support.design.testutils.TestUtilsActions.setTitle;
 import static android.support.test.espresso.Espresso.onView;
@@ -35,15 +37,10 @@
 import android.support.annotation.StringRes;
 import android.support.design.test.R;
 import android.support.design.testutils.Shakespeare;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralSwipeAction;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Swipe;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.text.TextUtils;
-import android.view.View;
 import android.widget.TextView;
 
 import org.hamcrest.Description;
@@ -64,38 +61,12 @@
 
     protected static void performVerticalSwipeUpGesture(@IdRes int containerId, final int swipeX,
             final int swipeStartY, final int swipeAmountY) {
-        onView(withId(containerId)).perform(new GeneralSwipeAction(
-                Swipe.SLOW,
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY };
-                    }
-                },
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY - swipeAmountY };
-                    }
-                }, Press.FINGER));
+        onView(withId(containerId)).perform(swipeUp(swipeX, swipeStartY, swipeAmountY));
     }
 
     protected static void performVerticalSwipeDownGesture(@IdRes int containerId, final int swipeX,
             final int swipeStartY, final int swipeAmountY) {
-        onView(withId(containerId)).perform(new GeneralSwipeAction(
-                Swipe.SLOW,
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY };
-                    }
-                },
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY + swipeAmountY };
-                    }
-                }, Press.FINGER));
+        onView(withId(containerId)).perform(swipeDown(swipeX, swipeStartY, swipeAmountY));
     }
 
     @CallSuper
diff --git a/design/tests/src/android/support/design/widget/AppBarLayoutCollapsePinTestActivity.java b/design/tests/src/android/support/design/widget/AppBarLayoutCollapsePinTestActivity.java
new file mode 100644
index 0000000..38ea4fc
--- /dev/null
+++ b/design/tests/src/android/support/design/widget/AppBarLayoutCollapsePinTestActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import android.support.design.test.R;
+import android.support.v7.widget.Toolbar;
+
+public class AppBarLayoutCollapsePinTestActivity extends BaseTestActivity {
+
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.design_appbar_toolbar_collapse_pin_restore_test;
+    }
+
+    @Override
+    protected void onContentViewSet() {
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+        setSupportActionBar(toolbar);
+    }
+}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java
new file mode 100644
index 0000000..52f4ab2
--- /dev/null
+++ b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import static android.support.design.testutils.AppBarLayoutMatchers.isCollapsed;
+import static android.support.design.testutils.SwipeUtils.swipeUp;
+import static android.support.design.testutils.TestUtils.rotateOrientation;
+import static android.support.design.testutils.TestUtilsMatchers.hasZ;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import android.app.Activity;
+import android.support.design.test.R;
+
+import org.junit.Test;
+
+public class AppBarWithCollapsingToolbarStateRestoreTest
+        extends BaseInstrumentationTestCase<AppBarLayoutCollapsePinTestActivity> {
+
+    public AppBarWithCollapsingToolbarStateRestoreTest() {
+        super(AppBarLayoutCollapsePinTestActivity.class);
+    }
+
+    @Test
+    public void testRotateAndRestore() {
+        Activity activity = mActivityTestRule.getActivity();
+        final AppBarLayout appBar = (AppBarLayout) activity.findViewById(R.id.app_bar);
+
+        // Swipe up and collapse the AppBarLayout
+        onView(withId(R.id.coordinator_layout))
+                .perform(swipeUp(
+                        appBar.getLeft() + (appBar.getWidth() / 2),
+                        appBar.getBottom() + 20,
+                        appBar.getHeight()));
+        onView(withId(R.id.app_bar))
+                .check(matches(hasZ()))
+                .check(matches(isCollapsed()));
+
+        // Now rotate the Activity
+        rotateOrientation(activity);
+
+        // And check that the app bar still is restored correctly
+        onView(withId(R.id.app_bar))
+                .check(matches(hasZ()))
+                .check(matches(isCollapsed()));
+    }
+
+}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
index adcfee8..2db3471 100644
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
@@ -16,7 +16,10 @@
 
 package android.support.design.widget;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
 import android.os.Build;
 import android.os.SystemClock;
@@ -245,6 +248,111 @@
     }
 
     @Test
+    public void testScrollingToolbarEnterAlways() throws Throwable {
+        configureContent(R.layout.design_appbar_toolbar_collapse_scroll_enteralways,
+                R.string.design_appbar_collapsing_toolbar_scroll);
+
+        final int[] appbarOnScreenXY = new int[2];
+        final int[] coordinatorLayoutOnScreenXY = new int[2];
+        mAppBar.getLocationOnScreen(appbarOnScreenXY);
+        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
+
+        final int topInset = mAppBar.getTopInset();
+
+        final int originalAppbarTop = appbarOnScreenXY[1];
+        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
+        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
+
+        final int toolbarHeight = mToolbar.getHeight();
+        final int appbarHeight = mAppBar.getHeight();
+        final int longSwipeAmount = 3 * appbarHeight / 2;
+        final int reallyLongSwipeAmount = 2 * appbarHeight;
+        final int shortSwipeAmount = toolbarHeight;
+
+        assertAppBarElevation(mDefaultElevationValue);
+        assertScrimAlpha(0);
+
+        // Perform a swipe-up gesture across the horizontal center of the screen, starting from
+        // just below the AppBarLayout
+        performVerticalSwipeUpGesture(
+                R.id.coordinator_layout,
+                centerX,
+                originalAppbarBottom + 20,
+                longSwipeAmount);
+
+        mAppBar.getLocationOnScreen(appbarOnScreenXY);
+        // At this point the app bar should not be visually "present" on the screen, with its bottom
+        // edge aligned with the bottom of system status bar. If we're running on a device which
+        // supports a translucent status bar, we need to take the status bar height into account.
+        // Allow for off-by-a-pixel margin of error.
+        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight - topInset, 1);
+        assertAppBarElevation(mDefaultElevationValue);
+        assertScrimAlpha(255);
+
+        // Perform another swipe-up gesture
+        performVerticalSwipeUpGesture(
+                R.id.coordinator_layout,
+                centerX,
+                originalAppbarBottom,
+                shortSwipeAmount);
+
+        mAppBar.getLocationOnScreen(appbarOnScreenXY);
+        // At this point the app bar should still be off the screen. Allow for off-by-a-pixel
+        // margin of error.
+        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight - topInset, 1);
+        assertAppBarElevation(mDefaultElevationValue);
+        assertScrimAlpha(255);
+
+        // Perform a short swipe-down gesture across the horizontal center of the screen.
+        // Note that the swipe down is a bit longer than the swipe up to fully bring down
+        // the scrolled-away toolbar
+        performVerticalSwipeDownGesture(
+                R.id.coordinator_layout,
+                centerX,
+                originalAppbarBottom,
+                3 * shortSwipeAmount / 2);
+
+        mAppBar.getLocationOnScreen(appbarOnScreenXY);
+
+        // At this point the app bar should be visually below the system status bar as it
+        // in scrolling mode and we've swiped down, not fully but more than collapsed
+        assertThat(appbarOnScreenXY[1] + appbarHeight,
+                is(greaterThan(originalAppbarTop + toolbarHeight + topInset)));
+        assertAppBarElevation(mDefaultElevationValue);
+        assertScrimAlpha(255);
+
+        // Perform another swipe-down gesture across the horizontal center of the screen.
+        performVerticalSwipeDownGesture(
+                R.id.coordinator_layout,
+                centerX,
+                originalAppbarBottom,
+                reallyLongSwipeAmount);
+
+        mAppBar.getLocationOnScreen(appbarOnScreenXY);
+        // At this point the app bar should be in its original position.
+        // Allow for off-by-a-pixel margin of error.
+        assertEquals(originalAppbarTop, appbarOnScreenXY[1]);
+        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight);
+        assertAppBarElevation(mDefaultElevationValue);
+        assertScrimAlpha(0);
+
+        // Perform yet another swipe-down gesture across the horizontal center of the screen.
+        performVerticalSwipeDownGesture(
+                R.id.coordinator_layout,
+                centerX,
+                originalAppbarBottom,
+                longSwipeAmount);
+
+        mAppBar.getLocationOnScreen(appbarOnScreenXY);
+        // At this point the app bar should still be in its original position.
+        // Allow for off-by-a-pixel margin of error.
+        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
+        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
+        assertAppBarElevation(mDefaultElevationValue);
+        assertScrimAlpha(0);
+    }
+
+    @Test
     public void testPinnedToolbarAndAnchoredFab() throws Throwable {
         configureContent(R.layout.design_appbar_toolbar_collapse_pin_with_fab,
                 R.string.design_appbar_collapsing_toolbar_pin_fab);
diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
index f06a85a..dcbbfb3 100644
--- a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
+++ b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
@@ -38,6 +38,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.res.Resources;
+import android.os.Parcelable;
 import android.support.annotation.ColorInt;
 import android.support.design.test.R;
 import android.support.design.testutils.TestDrawable;
@@ -233,6 +234,29 @@
         assertEquals(3, mBottomNavigation.getMenu().size());
     }
 
+    @Test
+    @SmallTest
+    public void testSavedState() throws Throwable {
+        // Select an item other than the first
+        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
+                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
+        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
+        // Save the state
+        final Parcelable state = mBottomNavigation.onSaveInstanceState();
+
+        // Restore the state into a fresh BottomNavigationView
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                BottomNavigationView testView =
+                        new BottomNavigationView(mActivityTestRule.getActivity());
+                testView.inflateMenu(R.menu.bottom_navigation_view_content);
+                testView.onRestoreInstanceState(state);
+                assertTrue(testView.getMenu().findItem(R.id.destination_profile).isChecked());
+            }
+        });
+    }
+
     private void checkAndVerifyExclusiveItem(final Menu menu, final int id) throws Throwable {
         menu.findItem(id).setChecked(true);
         for (int i = 0; i < menu.size(); i++) {
diff --git a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java b/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
index 84c522c..4c6bbbf 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
@@ -21,6 +21,11 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.lessThan;
 import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.content.DialogInterface;
@@ -171,6 +176,40 @@
         }
     }
 
+    @SuppressWarnings("WrongConstant")
+    @Test
+    @MediumTest
+    public void testHideThenShow() throws Throwable {
+        // Hide the bottom sheet and wait for the dialog to be canceled.
+        final DialogInterface.OnCancelListener onCancelListener = mock(
+                DialogInterface.OnCancelListener.class);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                showDialog();
+                mDialog.setOnCancelListener(onCancelListener);
+            }
+        });
+        Espresso.onView(ViewMatchers.withId(R.id.design_bottom_sheet))
+                .perform(setState(BottomSheetBehavior.STATE_HIDDEN));
+        verify(onCancelListener, timeout(3000)).onCancel(any(DialogInterface.class));
+        // Reshow the same dialog instance and wait for the bottom sheet to be collapsed.
+        final BottomSheetBehavior.BottomSheetCallback callback = mock(
+                BottomSheetBehavior.BottomSheetCallback.class);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                BottomSheetBehavior.from(mDialog.findViewById(R.id.design_bottom_sheet))
+                        .setBottomSheetCallback(callback);
+                mDialog.show(); // Show the same dialog again.
+            }
+        });
+        verify(callback, timeout(3000)).onStateChanged(any(View.class),
+                eq(BottomSheetBehavior.STATE_SETTLING));
+        verify(callback, timeout(3000)).onStateChanged(any(View.class),
+                eq(BottomSheetBehavior.STATE_COLLAPSED));
+    }
+
     private void showDialog() {
         Context context = mActivityTestRule.getActivity();
         mDialog = new BottomSheetDialog(context);
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
index 1d4f0a7..73ad193 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
@@ -16,6 +16,7 @@
 
 package android.support.design.widget;
 
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.action.ViewActions.swipeUp;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
@@ -40,10 +41,11 @@
 import android.graphics.Rect;
 import android.support.design.test.R;
 import android.support.design.testutils.CoordinatorLayoutUtils;
+import android.support.design.testutils.CoordinatorLayoutUtils.DependentBehavior;
 import android.support.design.widget.CoordinatorLayout.Behavior;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SdkSuppress;
+import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.WindowInsetsCompat;
 import android.view.Gravity;
@@ -69,13 +71,13 @@
 
     @Before
     public void setup() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mInstrumentation = getInstrumentation();
     }
 
     @Test
     @SdkSuppress(minSdkVersion = 21)
     public void testSetFitSystemWindows() throws Throwable {
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Instrumentation instrumentation = getInstrumentation();
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
         final View view = new View(col.getContext());
 
@@ -128,6 +130,58 @@
     }
 
     @Test
+    public void testLayoutChildren() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+        final View view = new View(col.getContext());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(view, 100, 100);
+            }
+        });
+        instrumentation.waitForIdleSync();
+        int horizontallyCentered = (col.getWidth() - view.getWidth()) / 2;
+        int end = col.getWidth() - view.getWidth();
+        int verticallyCentered = (col.getHeight() - view.getHeight()) / 2;
+        int bottom = col.getHeight() - view.getHeight();
+        final int[][] testCases = {
+                // gravity, expected left, expected top
+                {Gravity.NO_GRAVITY, 0, 0},
+                {Gravity.LEFT, 0, 0},
+                {GravityCompat.START, 0, 0},
+                {Gravity.TOP, 0, 0},
+                {Gravity.CENTER, horizontallyCentered, verticallyCentered},
+                {Gravity.CENTER_HORIZONTAL, horizontallyCentered, 0},
+                {Gravity.CENTER_VERTICAL, 0, verticallyCentered},
+                {Gravity.RIGHT, end, 0},
+                {GravityCompat.END, end, 0},
+                {Gravity.BOTTOM, 0, bottom},
+                {Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, horizontallyCentered, bottom},
+                {Gravity.RIGHT | Gravity.CENTER_VERTICAL, end, verticallyCentered},
+        };
+        for (final int[] testCase : testCases) {
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    final CoordinatorLayout.LayoutParams lp =
+                            (CoordinatorLayout.LayoutParams) view.getLayoutParams();
+                    lp.gravity = testCase[0];
+                    view.setLayoutParams(lp);
+                }
+            });
+            instrumentation.waitForIdleSync();
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    assertThat("Gravity: " + testCase[0], view.getLeft(), is(testCase[1]));
+                    assertThat("Gravity: " + testCase[0], view.getTop(), is(testCase[2]));
+                }
+            });
+        }
+    }
+
+    @Test
     public void testInsetDependency() {
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
 
@@ -183,7 +237,7 @@
 
     @Test
     public void testInsetEdge() throws Throwable {
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Instrumentation instrumentation = getInstrumentation();
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
 
         final View insetView = new View(col.getContext());
@@ -236,7 +290,7 @@
 
     @Test
     public void testDependentViewChanged() throws Throwable {
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Instrumentation instrumentation = getInstrumentation();
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
 
         // Add two views, A & B, where B depends on A
@@ -250,7 +304,7 @@
         lpB.width = 100;
         lpB.height = 100;
         final CoordinatorLayout.Behavior behavior =
-                spy(new CoordinatorLayoutUtils.DependentBehavior(viewA));
+                spy(new DependentBehavior(viewA));
         lpB.setBehavior(behavior);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
@@ -282,7 +336,7 @@
 
     @Test
     public void testDependentViewRemoved() throws Throwable {
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Instrumentation instrumentation = getInstrumentation();
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
 
         // Add two views, A & B, where B depends on A
@@ -290,7 +344,7 @@
         final View viewB = new View(col.getContext());
         final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
         final CoordinatorLayout.Behavior behavior =
-                spy(new CoordinatorLayoutUtils.DependentBehavior(viewA));
+                spy(new DependentBehavior(viewA));
         lpB.setBehavior(behavior);
 
         mActivityTestRule.runOnUiThread(new Runnable() {
@@ -316,7 +370,7 @@
 
     @Test
     public void testGetDependenciesAfterDependentViewRemoved() throws Throwable {
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Instrumentation instrumentation = getInstrumentation();
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
 
         // Add two views, A & B, where B depends on A
@@ -572,6 +626,55 @@
     }
 
     @Test
+    public void testNestedScrollingTriggeringDependentViewChanged() throws Throwable {
+        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
+        final CoordinatorLayout col = activity.mCoordinatorLayout;
+
+        // First a NestedScrollView to trigger nested scrolling
+        final View scrollView = LayoutInflater.from(activity).inflate(
+                R.layout.include_nestedscrollview, col, false);
+
+        // Now create a View and Behavior which depend on the scrollview
+        final ImageView dependentView = new ImageView(activity);
+        final CoordinatorLayout.Behavior dependentBehavior = spy(new DependentBehavior(scrollView));
+
+        // Finally a view which accepts nested scrolling in the CoordinatorLayout
+        final ImageView nestedScrollAwareView = new ImageView(activity);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // First add the ScrollView
+                col.addView(scrollView);
+
+                // Now add the view which depends on the scrollview
+                CoordinatorLayout.LayoutParams clp = new CoordinatorLayout.LayoutParams(200, 200);
+                clp.setBehavior(dependentBehavior);
+                col.addView(dependentView, clp);
+
+                // Now add the nested scrolling aware view
+                clp = new CoordinatorLayout.LayoutParams(200, 200);
+                clp.setBehavior(new NestedScrollingBehavior());
+                col.addView(nestedScrollAwareView, clp);
+            }
+        });
+
+        // Wait for any layouts, and reset the Behavior so that the call counts are 0
+        getInstrumentation().waitForIdleSync();
+        reset(dependentBehavior);
+
+        // Now vertically swipe up on the NSV, causing nested scrolling to occur
+        onView(withId(R.id.nested_scrollview)).perform(swipeUp());
+
+        // Verify that the Behavior's onDependentViewChanged is not called due to the
+        // nested scroll
+        verify(dependentBehavior, never()).onDependentViewChanged(
+                eq(col), // parent
+                eq(dependentView), // child
+                eq(scrollView)); // axes
+    }
+
+    @Test
     public void testDodgeInsetViewWithEmptyBounds() throws Throwable {
         final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
 
@@ -614,9 +717,9 @@
                 .getInsetDodgeRect(same(col), same(view), any(Rect.class));
     }
 
-    public static class NestedScrollingBehavior extends CoordinatorLayout.Behavior<ImageView> {
+    public static class NestedScrollingBehavior extends CoordinatorLayout.Behavior<View> {
         @Override
-        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, ImageView child,
+        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child,
                 View directTargetChild, View target, int nestedScrollAxes) {
             // Return true so that we always accept nested scroll events
             return true;
diff --git a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java b/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
index 069055b..e8cc701 100644
--- a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
+++ b/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
@@ -33,11 +33,15 @@
 import static android.support.design.testutils.TestUtilsMatchers.withFabContentHeight;
 import static android.support.design.widget.DesignViewActions.setVisibility;
 import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
 
 import static org.hamcrest.Matchers.not;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
 import android.content.res.ColorStateList;
@@ -229,6 +233,19 @@
     }
 
     @Test
+    public void testOnClickListener() {
+        final View.OnClickListener listener = mock(View.OnClickListener.class);
+        final View view = mActivityTestRule.getActivity().findViewById(R.id.fab_standard);
+        view.setOnClickListener(listener);
+
+        // Click on the fab
+        onView(withId(R.id.fab_standard)).perform(click());
+
+        // And verify that the listener was invoked once
+        verify(listener, times(1)).onClick(view);
+    }
+
+    @Test
     public void testSetCompatElevation() {
         onView(withId(R.id.fab_standard))
                 .perform(setEnabled(false))
diff --git a/design/tests/src/android/support/design/widget/SnackbarTest.java b/design/tests/src/android/support/design/widget/SnackbarTest.java
index 23092e8..5f5682c 100644
--- a/design/tests/src/android/support/design/widget/SnackbarTest.java
+++ b/design/tests/src/android/support/design/widget/SnackbarTest.java
@@ -46,6 +46,10 @@
 import android.support.design.testutils.SnackbarUtils;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.ViewInteraction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralSwipeAction;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swipe;
 import android.support.test.filters.MediumTest;
 import android.support.v4.view.ViewCompat;
 import android.text.TextUtils;
@@ -242,6 +246,41 @@
     }
 
     @Test
+    public void testSwipeUpDismissesViaTimeout() throws Throwable {
+        verifyDismissCallback(
+                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
+                // This is a swipe up, from the middle center of the view, to above the view
+                // (outside the bounds)
+                new GeneralSwipeAction(
+                        Swipe.SLOW,
+                        new CoordinatesProvider() {
+                            @Override
+                            public float[] calculateCoordinates(View view) {
+                                final int[] loc = new int[2];
+                                view.getLocationOnScreen(loc);
+                                return new float[]{
+                                        loc[0] + view.getWidth() / 2,
+                                        loc[1] + view.getHeight() / 2};
+                            }
+                        },
+                        new CoordinatesProvider() {
+                            @Override
+                            public float[] calculateCoordinates(View view) {
+                                final int[] loc = new int[2];
+                                view.getLocationOnScreen(loc);
+                                return new float[]{
+                                        loc[0] + view.getWidth() / 2,
+                                        loc[1] - view.getHeight()};
+                            }
+                        },
+                        Press.FINGER
+                ),
+                null,
+                Snackbar.LENGTH_SHORT,
+                Snackbar.Callback.DISMISS_EVENT_TIMEOUT);
+    }
+
+    @Test
     public void testDismissViaAnotherSnackbar() throws Throwable {
         final Snackbar anotherSnackbar =
                 Snackbar.make(mCoordinatorLayout, "A different message", Snackbar.LENGTH_SHORT);
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java b/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
index 4944170..2ba1e6e 100755
--- a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
@@ -460,6 +460,12 @@
     }
 
     @Test
+    public void testTextSetViaAttributeCollapsedHint() {
+        onView(withId(R.id.textinput_with_text))
+                .check(isHintExpanded(false));
+    }
+
+    @Test
     public void testFocusMovesToEditTextWithPasswordEnabled() {
         // Focus the preceding EditText
         onView(withId(R.id.textinput_edittext))
diff --git a/exifinterface/Android.mk b/exifinterface/Android.mk
index 9da8bc5..4d5887c 100644
--- a/exifinterface/Android.mk
+++ b/exifinterface/Android.mk
@@ -25,6 +25,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
diff --git a/exifinterface/AndroidManifest-make.xml b/exifinterface/AndroidManifest-make.xml
new file mode 100644
index 0000000..4812a71
--- /dev/null
+++ b/exifinterface/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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"
+          package="android.support.exifinterface">
+    <uses-sdk android:minSdkVersion="9"/>
+    <application />
+</manifest>
diff --git a/exifinterface/AndroidManifest.xml b/exifinterface/AndroidManifest.xml
index 4812a71..bacbdbe 100644
--- a/exifinterface/AndroidManifest.xml
+++ b/exifinterface/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.exifinterface">
     <uses-sdk android:minSdkVersion="9"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/exifinterface/build.gradle b/exifinterface/build.gradle
index 42f50c1..f6fd633 100644
--- a/exifinterface/build.gradle
+++ b/exifinterface/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'exifinterface'
 
 dependencies {
@@ -33,28 +32,11 @@
     }
     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);
 }
 
diff --git a/exifinterface/src/android/support/media/ExifInterface.java b/exifinterface/src/android/support/media/ExifInterface.java
index ae9d842..fccab43 100644
--- a/exifinterface/src/android/support/media/ExifInterface.java
+++ b/exifinterface/src/android/support/media/ExifInterface.java
@@ -658,9 +658,9 @@
         }
 
         private Object getValue(ByteOrder byteOrder) {
+            ByteOrderedDataInputStream inputStream = null;
             try {
-                ByteOrderedDataInputStream inputStream =
-                        new ByteOrderedDataInputStream(bytes);
+                inputStream = new ByteOrderedDataInputStream(bytes);
                 inputStream.setByteOrder(byteOrder);
                 switch (format) {
                     case IFD_FORMAT_BYTE:
@@ -768,6 +768,14 @@
             } catch (IOException e) {
                 Log.w(TAG, "IOException occurred during reading a value", e);
                 return null;
+            } finally {
+                if (inputStream != null) {
+                    try {
+                        inputStream.close();
+                    } catch (IOException e) {
+                        Log.e(TAG, "IOException occurred while closing InputStream", e);
+                    }
+                }
             }
         }
 
@@ -1517,8 +1525,8 @@
                         final Rational[] rationalArray = new Rational[values.length];
                         for (int j = 0; j < values.length; ++j) {
                             final String[] numbers = values[j].split("/");
-                            rationalArray[j] = new Rational(Long.parseLong(numbers[0]),
-                                    Long.parseLong(numbers[1]));
+                            rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
+                                    (long) Double.parseDouble(numbers[1]));
                         }
                         mAttributes[i].put(tag,
                                 ExifAttribute.createURational(rationalArray, mExifByteOrder));
@@ -1529,8 +1537,8 @@
                         final Rational[] rationalArray = new Rational[values.length];
                         for (int j = 0; j < values.length; ++j) {
                             final String[] numbers = values[j].split("/");
-                            rationalArray[j] = new Rational(Long.parseLong(numbers[0]),
-                                    Long.parseLong(numbers[1]));
+                            rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
+                                    (long) Double.parseDouble(numbers[1]));
                         }
                         mAttributes[i].put(tag,
                                 ExifAttribute.createSRational(rationalArray, mExifByteOrder));
@@ -2040,6 +2048,7 @@
         signatureInputStream.setByteOrder(mExifByteOrder);
 
         short orfSignature = signatureInputStream.readShort();
+        signatureInputStream.close();
         return orfSignature == ORF_SIGNATURE_1 || orfSignature == ORF_SIGNATURE_2;
     }
 
@@ -2056,6 +2065,7 @@
         signatureInputStream.setByteOrder(mExifByteOrder);
 
         short signatureByte = signatureInputStream.readShort();
+        signatureInputStream.close();
         return signatureByte == RW2_SIGNATURE;
     }
 
@@ -3341,8 +3351,8 @@
             String[] rationalNumber = entryValue.split("/");
             if (rationalNumber.length == 2) {
                 try {
-                    long numerator = Long.parseLong(rationalNumber[0]);
-                    long denominator = Long.parseLong(rationalNumber[1]);
+                    long numerator = (long) Double.parseDouble(rationalNumber[0]);
+                    long denominator = (long) Double.parseDouble(rationalNumber[1]);
                     if (numerator < 0L || denominator < 0L) {
                         return new Pair<>(IFD_FORMAT_SRATIONAL, -1);
                     }
diff --git a/fragment/Android.mk b/fragment/Android.mk
index a41b0c2..f55cfb7 100644
--- a/fragment/Android.mk
+++ b/fragment/Android.mk
@@ -36,6 +36,7 @@
     $(call all-java-files-under, api21) \
     $(call all-java-files-under, java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-ui \
diff --git a/fragment/AndroidManifest-make.xml b/fragment/AndroidManifest-make.xml
new file mode 100644
index 0000000..54e61d3
--- /dev/null
+++ b/fragment/AndroidManifest-make.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.fragment">
+    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.fragment"/>
+    <application />
+</manifest>
diff --git a/fragment/AndroidManifest.xml b/fragment/AndroidManifest.xml
index 54e61d3..9b34e14 100644
--- a/fragment/AndroidManifest.xml
+++ b/fragment/AndroidManifest.xml
@@ -17,5 +17,6 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.fragment">
     <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.fragment"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 26e9f1c..7c9098a 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -18,9 +18,6 @@
     testCompile 'junit:junit:4.12'
 }
 
-sourceCompatibility = JavaVersion.VERSION_1_7
-targetCompatibility = JavaVersion.VERSION_1_7
-
 android {
     compileSdkVersion project.ext.currentSdk
 
@@ -50,11 +47,6 @@
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
-
-    testOptions {
-        unitTests.returnDefaultValues = true
-        compileSdkVersion project.ext.currentSdk
-    }
 }
 
 android.libraryVariants.all { variant ->
@@ -65,22 +57,6 @@
     }
     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
@@ -88,7 +64,6 @@
         exclude('android/service/media/**')
     }
 
-    artifacts.add('archives', javadocJarTask);
     artifacts.add('archives', sourcesJarTask);
 }
 
diff --git a/fragment/java/android/support/v4/app/BackStackRecord.java b/fragment/java/android/support/v4/app/BackStackRecord.java
index 3b41d60..326521a 100644
--- a/fragment/java/android/support/v4/app/BackStackRecord.java
+++ b/fragment/java/android/support/v4/app/BackStackRecord.java
@@ -639,6 +639,7 @@
             LogWriter logw = new LogWriter(TAG);
             PrintWriter pw = new PrintWriter(logw);
             dump("  ", null, pw, null);
+            pw.close();
         }
         mCommitted = true;
         if (mAddToBackStack) {
diff --git a/fragment/java/android/support/v4/app/Fragment.java b/fragment/java/android/support/v4/app/Fragment.java
index 881c2b4..06d0b1e 100644
--- a/fragment/java/android/support/v4/app/Fragment.java
+++ b/fragment/java/android/support/v4/app/Fragment.java
@@ -2150,6 +2150,9 @@
     }
 
     void instantiateChildFragmentManager() {
+        if (mHost == null) {
+            throw new IllegalStateException("Fragment has not been attached yet.");
+        }
         mChildFragmentManager = new FragmentManagerImpl();
         mChildFragmentManager.attachController(mHost, new FragmentContainer() {
             @Override
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 8aaf53f..b385461 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -2855,6 +2855,7 @@
                     LogWriter logw = new LogWriter(TAG);
                     PrintWriter pw = new PrintWriter(logw);
                     bse.dump("  ", pw, false);
+                    pw.close();
                 }
                 mBackStack.add(bse);
                 if (bse.mIndex >= 0) {
diff --git a/fragment/tests/java/android/support/v4/app/FragmentOptimizationTest.java b/fragment/tests/java/android/support/v4/app/FragmentOptimizationTest.java
index 06abd69..13901c4 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentOptimizationTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentOptimizationTest.java
@@ -15,11 +15,14 @@
  */
 package android.support.v4.app;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
 import android.support.fragment.test.R;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
@@ -648,38 +651,30 @@
 
     // Test that a fragment view that is created with focus has focus after the transaction
     // completes.
+    @UiThreadTest
     @Test
     public void focusedView() throws Throwable {
-        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+        mActivityRule.getActivity().setContentView(R.layout.double_container);
         mContainer = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.fragmentContainer1);
-        final EditText firstEditText = new EditText(mContainer.getContext());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mContainer.addView(firstEditText);
-                firstEditText.requestFocus();
-            }
-        });
+        EditText firstEditText = new EditText(mContainer.getContext());
+        mContainer.addView(firstEditText);
+        firstEditText.requestFocus();
+
         assertTrue(firstEditText.isFocused());
         final CountCallsFragment fragment1 = new CountCallsFragment();
         final CountCallsFragment fragment2 = new CountCallsFragment();
         fragment2.setLayoutId(R.layout.with_edit_text);
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mFM.beginTransaction()
-                        .add(R.id.fragmentContainer2, fragment1)
-                        .addToBackStack(null)
-                        .setAllowOptimization(true)
-                        .commit();
-                mFM.beginTransaction()
-                        .replace(R.id.fragmentContainer2, fragment2)
-                        .addToBackStack(null)
-                        .setAllowOptimization(true)
-                        .commit();
-                mFM.executePendingTransactions();
-            }
-        });
+        mFM.beginTransaction()
+                .add(R.id.fragmentContainer2, fragment1)
+                .addToBackStack(null)
+                .setAllowOptimization(true)
+                .commit();
+        mFM.beginTransaction()
+                .replace(R.id.fragmentContainer2, fragment2)
+                .addToBackStack(null)
+                .setAllowOptimization(true)
+                .commit();
+        mFM.executePendingTransactions();
         final View editText = fragment2.getView().findViewById(R.id.editText);
         assertTrue(editText.isFocused());
         assertFalse(firstEditText.isFocused());
diff --git a/gradle.properties b/gradle.properties
index 34b3995..fb870a9 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,4 @@
 org.gradle.jvmargs=-Xmx3g
 org.gradle.daemon=true
-org.gradle.configureondemand=true
\ No newline at end of file
+org.gradle.configureondemand=true
+org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ccfc973..84939b4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=../../../../tools/external/gradle/gradle-3.2-bin.zip
+distributionUrl=../../../../tools/external/gradle/gradle-3.3-bin.zip
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
index f58493b..78652aa 100644
--- a/graphics/drawable/Android.mk
+++ b/graphics/drawable/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, static/src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/static/res
-LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := static/AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
@@ -44,7 +44,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, animated/src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/animated/res
-LOCAL_MANIFEST_FILE := animated/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := animated/AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-vectordrawable \
diff --git a/graphics/drawable/animated/AndroidManifest-make.xml b/graphics/drawable/animated/AndroidManifest-make.xml
new file mode 100644
index 0000000..98f9e17
--- /dev/null
+++ b/graphics/drawable/animated/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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"
+          package="android.support.graphics.drawable.animated">
+    <application/>
+</manifest>
diff --git a/graphics/drawable/animated/AndroidManifest.xml b/graphics/drawable/animated/AndroidManifest.xml
index 98f9e17..58017dc 100644
--- a/graphics/drawable/animated/AndroidManifest.xml
+++ b/graphics/drawable/animated/AndroidManifest.xml
@@ -16,5 +16,6 @@
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.graphics.drawable.animated">
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application/>
 </manifest>
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index bb110a1..10d112a 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'animated-vector-drawable'
 
 dependencies {
@@ -41,14 +40,6 @@
         additionalParameters "--no-version-vectors"
     }
 
-    packagingOptions {
-        exclude 'LICENSE.txt'
-    }
-
-    testOptions {
-        unitTests.returnDefaultValues = true
-    }
-
     buildTypes.all {
         consumerProguardFiles 'proguard-rules.pro'
     }
@@ -62,28 +53,11 @@
     }
     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);
 }
 
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 8c0a7be..fe60272 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -397,6 +397,7 @@
                             Animator objectAnimator = AnimatorInflater.loadAnimator(mContext, id);
                             setupAnimatorsForTarget(target, objectAnimator);
                         } else {
+                            a.recycle();
                             throw new IllegalStateException("Context can't be null when inflating" +
                                     " animators");
                         }
diff --git a/graphics/drawable/static/AndroidManifest-make.xml b/graphics/drawable/static/AndroidManifest-make.xml
new file mode 100644
index 0000000..8674cb4
--- /dev/null
+++ b/graphics/drawable/static/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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"
+    package="android.support.graphics.drawable">
+    <application/>
+</manifest>
diff --git a/graphics/drawable/static/AndroidManifest.xml b/graphics/drawable/static/AndroidManifest.xml
index e91290d..0383e4c 100644
--- a/graphics/drawable/static/AndroidManifest.xml
+++ b/graphics/drawable/static/AndroidManifest.xml
@@ -14,6 +14,8 @@
    See the License for the specific language governing permissions and
    limitations under the License.
   -->
-<manifest package="android.support.graphics.drawable">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.support.graphics.drawable">
     <application/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
 </manifest>
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index 2c72f9f..fdb306c 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -42,14 +42,6 @@
     aaptOptions {
         additionalParameters "--no-version-vectors"
     }
-
-    packagingOptions {
-        exclude 'LICENSE.txt'
-    }
-
-    testOptions {
-        unitTests.returnDefaultValues = true
-    }
 }
 
 android.libraryVariants.all { variant ->
@@ -60,28 +52,11 @@
     }
     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);
 }
 
diff --git a/media-compat/Android.mk b/media-compat/Android.mk
index 52dc3d8..0050ea4 100644
--- a/media-compat/Android.mk
+++ b/media-compat/Android.mk
@@ -38,6 +38,7 @@
     $(call all-java-files-under,java) \
     $(call all-Iaidl-files-under,java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/media-compat/AndroidManifest-make.xml b/media-compat/AndroidManifest-make.xml
new file mode 100644
index 0000000..c971549
--- /dev/null
+++ b/media-compat/AndroidManifest-make.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.mediacompat">
+    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.mediacompat"/>
+    <application />
+</manifest>
diff --git a/media-compat/AndroidManifest.xml b/media-compat/AndroidManifest.xml
index c971549..5f7b051 100644
--- a/media-compat/AndroidManifest.xml
+++ b/media-compat/AndroidManifest.xml
@@ -17,5 +17,6 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.mediacompat">
     <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.mediacompat"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index 9bec2a3..8dd44bf 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -15,9 +15,6 @@
     androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
 }
 
-sourceCompatibility = JavaVersion.VERSION_1_7
-targetCompatibility = JavaVersion.VERSION_1_7
-
 android {
     compileSdkVersion project.ext.currentSdk
 
@@ -61,22 +58,6 @@
     }
     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
@@ -84,7 +65,6 @@
         exclude('android/service/media/**')
     }
 
-    artifacts.add('archives', javadocJarTask);
     artifacts.add('archives', sourcesJarTask);
 }
 
diff --git a/percent/Android.mk b/percent/Android.mk
index b569224..aaeb65a 100644
--- a/percent/Android.mk
+++ b/percent/Android.mk
@@ -27,6 +27,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := android-support-v4
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
diff --git a/percent/AndroidManifest-make.xml b/percent/AndroidManifest-make.xml
new file mode 100644
index 0000000..e979013
--- /dev/null
+++ b/percent/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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"
+          package="android.support.percent">
+    <uses-sdk android:minSdkVersion="9"/>
+    <application />
+</manifest>
diff --git a/percent/AndroidManifest.xml b/percent/AndroidManifest.xml
index e979013..0d55165 100644
--- a/percent/AndroidManifest.xml
+++ b/percent/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.percent">
     <uses-sdk android:minSdkVersion="9"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/percent/build.gradle b/percent/build.gradle
index c3f386e..b120075 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'percent'
 
 dependencies {
@@ -53,28 +52,11 @@
     }
     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);
 }
 
diff --git a/recommendation/Android.mk b/recommendation/Android.mk
index 0e0a9d7..67721bb 100644
--- a/recommendation/Android.mk
+++ b/recommendation/Android.mk
@@ -27,6 +27,7 @@
 LOCAL_SDK_VERSION := 21
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v4 \
     android-support-annotations
diff --git a/recommendation/AndroidManifest-make.xml b/recommendation/AndroidManifest-make.xml
new file mode 100644
index 0000000..ef1223e
--- /dev/null
+++ b/recommendation/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.recommendation">
+    <uses-sdk android:minSdkVersion="21"/>
+    <application />
+</manifest>
diff --git a/recommendation/AndroidManifest.xml b/recommendation/AndroidManifest.xml
index ef1223e..e36c822 100644
--- a/recommendation/AndroidManifest.xml
+++ b/recommendation/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.recommendation">
     <uses-sdk android:minSdkVersion="21"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index 75d68d1..dadad58 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'recommendation'
 
 dependencies {
@@ -41,27 +40,10 @@
     }
     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);
 }
diff --git a/transition/Android.mk b/transition/Android.mk
index c468ef1..aefedd7 100644
--- a/transition/Android.mk
+++ b/transition/Android.mk
@@ -34,6 +34,7 @@
     $(call all-java-files-under,api23) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations \
     android-support-v4
diff --git a/transition/AndroidManifest-make.xml b/transition/AndroidManifest-make.xml
new file mode 100644
index 0000000..672e1b1
--- /dev/null
+++ b/transition/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.transition">
+    <uses-sdk android:minSdkVersion="14"/>
+    <application />
+</manifest>
diff --git a/transition/AndroidManifest.xml b/transition/AndroidManifest.xml
index 672e1b1..1059f63 100644
--- a/transition/AndroidManifest.xml
+++ b/transition/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.transition">
     <uses-sdk android:minSdkVersion="14"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/transition/build.gradle b/transition/build.gradle
index 05675f9..2f47f83 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -61,28 +61,11 @@
     }
     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);
 }
 
diff --git a/v13/Android.mk b/v13/Android.mk
index 1b30d99..9411930 100644
--- a/v13/Android.mk
+++ b/v13/Android.mk
@@ -34,6 +34,7 @@
         $(call all-java-files-under, api25) \
         $(call all-java-files-under, java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 # Some projects expect to inherit android-support-v4 from
 # android-support-v13, so we need to keep it static until they can be fixed.
 LOCAL_STATIC_ANDROID_LIBRARIES := \
diff --git a/v13/AndroidManifest-make.xml b/v13/AndroidManifest-make.xml
new file mode 100644
index 0000000..ea25a74
--- /dev/null
+++ b/v13/AndroidManifest-make.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.v13">
+    <uses-sdk android:minSdkVersion="13" tools:overrideLibrary="android.support.v13"/>
+    <application />
+</manifest>
diff --git a/v13/AndroidManifest.xml b/v13/AndroidManifest.xml
index ea25a74..7449688 100644
--- a/v13/AndroidManifest.xml
+++ b/v13/AndroidManifest.xml
@@ -17,5 +17,6 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v13">
     <uses-sdk android:minSdkVersion="13" tools:overrideLibrary="android.support.v13"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}"/>
     <application />
 </manifest>
diff --git a/v13/build.gradle b/v13/build.gradle
index 85aa8a8..fb1c25d 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -55,28 +55,11 @@
     }
     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);
 }
 
diff --git a/v14/preference/Android.mk b/v14/preference/Android.mk
index 7a0b846..195e8a3 100644
--- a/v14/preference/Android.mk
+++ b/v14/preference/Android.mk
@@ -31,6 +31,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-preference \
     android-support-v7-appcompat \
diff --git a/v14/preference/AndroidManifest-make.xml b/v14/preference/AndroidManifest-make.xml
new file mode 100644
index 0000000..b917bb4
--- /dev/null
+++ b/v14/preference/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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"
+    package="android.support.v14.preference">
+    <uses-sdk android:minSdkVersion="14" />
+    <application />
+</manifest>
diff --git a/v14/preference/AndroidManifest.xml b/v14/preference/AndroidManifest.xml
index 8b502c9..74cff2e 100644
--- a/v14/preference/AndroidManifest.xml
+++ b/v14/preference/AndroidManifest.xml
@@ -1,8 +1,21 @@
 <?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"
-    package="android.support.v14.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
+    package="android.support.v14.preference">
     <uses-sdk android:minSdkVersion="14" />
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index a7e63d5..5583e93 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -14,10 +14,7 @@
  * limitations under the License
  */
 
-
-
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'preference-v14'
 
 dependencies {
@@ -62,28 +59,11 @@
     }
     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);
 }
 
diff --git a/v17/leanback/Android.mk b/v17/leanback/Android.mk
index c6a50b4..d91436e 100644
--- a/v17/leanback/Android.mk
+++ b/v17/leanback/Android.mk
@@ -35,6 +35,7 @@
     $(call all-java-files-under, api23) \
     $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-recyclerview \
     android-support-compat \
diff --git a/v17/leanback/AndroidManifest-make.xml b/v17/leanback/AndroidManifest-make.xml
new file mode 100644
index 0000000..20ef094
--- /dev/null
+++ b/v17/leanback/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.v17.leanback">
+    <uses-sdk android:minSdkVersion="17"/>
+    <application />
+</manifest>
diff --git a/v17/leanback/AndroidManifest.xml b/v17/leanback/AndroidManifest.xml
index 20ef094..ded4ce8 100644
--- a/v17/leanback/AndroidManifest.xml
+++ b/v17/leanback/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v17.leanback">
     <uses-sdk android:minSdkVersion="17"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index f5befa7..9ed65a8 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -64,28 +64,11 @@
     }
     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);
 }
 
diff --git a/v17/leanback/generatev4.py b/v17/leanback/generatev4.py
index 2e1eaeb..9eb5932 100755
--- a/v17/leanback/generatev4.py
+++ b/v17/leanback/generatev4.py
@@ -16,6 +16,7 @@
 
 import os
 import sys
+import re
 
 print "Generate v4 fragment related code for leanback"
 
@@ -41,6 +42,7 @@
         line = line.replace('activity.getFragmentManager()', 'activity.getSupportFragmentManager()')
         line = line.replace('Activity activity', 'FragmentActivity activity')
         line = line.replace('(Activity', '(FragmentActivity')
+        line = re.sub(r'FragmentUtil.getContext\(.*this\)', 'getContext()', line);
         outfile.write(line)
     file.close()
     outfile.close()
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 3b4c851..8ab731f 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
@@ -219,7 +219,7 @@
             @Override
             public boolean onPreDraw() {
                 view.getViewTreeObserver().removeOnPreDrawListener(this);
-                if (getActivity() == null || getView() == null) {
+                if (FragmentUtil.getContext(BaseFragment.this) == null || getView() == null) {
                     // bail out if fragment is destroyed immediately after startEntranceTransition
                     return true;
                 }
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 8de54a7..7d08738 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
@@ -222,7 +222,7 @@
             @Override
             public boolean onPreDraw() {
                 view.getViewTreeObserver().removeOnPreDrawListener(this);
-                if (getActivity() == null || getView() == null) {
+                if (getContext() == null || getView() == null) {
                     // bail out if fragment is destroyed immediately after startEntranceTransition
                     return true;
                 }
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 fc6561e..24b1a85 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -19,6 +19,7 @@
 import android.app.FragmentManager;
 import android.app.FragmentManager.BackStackEntry;
 import android.app.FragmentTransaction;
+import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Rect;
@@ -1056,12 +1057,13 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        TypedArray ta = getActivity().obtainStyledAttributes(R.styleable.LeanbackTheme);
+        final Context context = FragmentUtil.getContext(this);
+        TypedArray ta = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
         mContainerListMarginStart = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginStart, getActivity().getResources()
+                R.styleable.LeanbackTheme_browseRowsMarginStart, context.getResources()
                 .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
         mContainerListAlignTop = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginTop, getActivity().getResources()
+                R.styleable.LeanbackTheme_browseRowsMarginTop, context.getResources()
                 .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
         ta.recycle();
 
@@ -1223,7 +1225,7 @@
     }
 
     void createHeadersTransition() {
-        mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
+        mHeadersTransition = TransitionHelper.loadTransition(FragmentUtil.getContext(this),
                 mShowingHeaders
                         ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
 
@@ -1657,7 +1659,7 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(FragmentUtil.getContext(this),
                 R.transition.lb_browse_entrance_transition);
     }
 
@@ -1740,7 +1742,7 @@
 
         @Override
         public boolean onPreDraw() {
-            if (getView() == null || getActivity() == null) {
+            if (getView() == null || FragmentUtil.getContext(BrowseFragment.this) == null) {
                 mView.getViewTreeObserver().removeOnPreDrawListener(this);
                 return true;
             }
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 7bcc43d..b73d23d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -22,6 +22,7 @@
 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.graphics.Color;
 import android.graphics.Rect;
@@ -1059,12 +1060,13 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        TypedArray ta = getActivity().obtainStyledAttributes(R.styleable.LeanbackTheme);
+        final Context context = getContext();
+        TypedArray ta = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
         mContainerListMarginStart = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginStart, getActivity().getResources()
+                R.styleable.LeanbackTheme_browseRowsMarginStart, context.getResources()
                 .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
         mContainerListAlignTop = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginTop, getActivity().getResources()
+                R.styleable.LeanbackTheme_browseRowsMarginTop, context.getResources()
                 .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
         ta.recycle();
 
@@ -1226,7 +1228,7 @@
     }
 
     void createHeadersTransition() {
-        mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
+        mHeadersTransition = TransitionHelper.loadTransition(getContext(),
                 mShowingHeaders
                         ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
 
@@ -1660,7 +1662,7 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(getContext(),
                 R.transition.lb_browse_entrance_transition);
     }
 
@@ -1743,7 +1745,7 @@
 
         @Override
         public boolean onPreDraw() {
-            if (getView() == null || getActivity() == null) {
+            if (getView() == null || getContext() == null) {
                 mView.getViewTreeObserver().removeOnPreDrawListener(this);
                 return true;
             }
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 fcb3fa9..f73cee6 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
@@ -473,7 +473,7 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(FragmentUtil.getContext(this),
                 R.transition.lb_details_enter_transition);
     }
 
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 a9bbf28..ee63156 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -476,7 +476,7 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(getContext(),
                 R.transition.lb_details_enter_transition);
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/FragmentUtil.java b/v17/leanback/src/android/support/v17/leanback/app/FragmentUtil.java
new file mode 100644
index 0000000..23c6039
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/FragmentUtil.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.annotation.TargetApi;
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Build;
+
+class FragmentUtil {
+
+    @TargetApi(23)
+    private static Context getContextNew(Fragment fragment) {
+        return fragment.getContext();
+    }
+
+    public static Context getContext(Fragment fragment) {
+        if (Build.VERSION.SDK_INT >= 23) {
+            return getContextNew(fragment);
+        } else {
+            return fragment.getActivity();
+        }
+    }
+}
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 da44fde..bab48bd 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
@@ -1129,7 +1129,7 @@
         } else {
             // when there are two actions panel, we need adjust the weight of action to
             // guidedActionContentWidthWeightTwoPanels.
-            Context ctx = mThemeWrapper != null ? mThemeWrapper : getActivity();
+            Context ctx = mThemeWrapper != null ? mThemeWrapper : FragmentUtil.getContext(this);
             TypedValue typedValue = new TypedValue();
             if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
                     typedValue, true)) {
@@ -1327,18 +1327,18 @@
     private void resolveTheme() {
         // Look up the guidedStepTheme in the currently specified theme.  If it exists,
         // replace the theme with its value.
-        Activity activity = getActivity();
+        Context context = FragmentUtil.getContext(this);
         int theme = onProvideTheme();
-        if (theme == -1 && !isGuidedStepTheme(activity)) {
+        if (theme == -1 && !isGuidedStepTheme(context)) {
             // 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);
+            boolean found = context.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);
+                        new ContextThemeWrapper(context, typedValue.resourceId);
                 if (isGuidedStepTheme(themeWrapper)) {
                     mThemeWrapper = themeWrapper;
                 } else {
@@ -1350,7 +1350,7 @@
                 Log.e(TAG, "GuidedStepFragment does not have an appropriate theme set.");
             }
         } else if (theme != -1) {
-            mThemeWrapper = new ContextThemeWrapper(activity, theme);
+            mThemeWrapper = new ContextThemeWrapper(context, theme);
         }
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
index 32de1fd..f68366c 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -1132,7 +1132,7 @@
         } else {
             // when there are two actions panel, we need adjust the weight of action to
             // guidedActionContentWidthWeightTwoPanels.
-            Context ctx = mThemeWrapper != null ? mThemeWrapper : getActivity();
+            Context ctx = mThemeWrapper != null ? mThemeWrapper : getContext();
             TypedValue typedValue = new TypedValue();
             if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
                     typedValue, true)) {
@@ -1330,18 +1330,18 @@
     private void resolveTheme() {
         // Look up the guidedStepTheme in the currently specified theme.  If it exists,
         // replace the theme with its value.
-        FragmentActivity activity = getActivity();
+        Context context = getContext();
         int theme = onProvideTheme();
-        if (theme == -1 && !isGuidedStepTheme(activity)) {
+        if (theme == -1 && !isGuidedStepTheme(context)) {
             // 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);
+            boolean found = context.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);
+                        new ContextThemeWrapper(context, typedValue.resourceId);
                 if (isGuidedStepTheme(themeWrapper)) {
                     mThemeWrapper = themeWrapper;
                 } else {
@@ -1353,7 +1353,7 @@
                 Log.e(TAG, "GuidedStepSupportFragment does not have an appropriate theme set.");
             }
         } else if (theme != -1) {
-            mThemeWrapper = new ContextThemeWrapper(activity, theme);
+            mThemeWrapper = new ContextThemeWrapper(context, theme);
         }
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/ListRowDataAdapter.java b/v17/leanback/src/android/support/v17/leanback/app/ListRowDataAdapter.java
index 1f2788f..f9af12f 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/ListRowDataAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/ListRowDataAdapter.java
@@ -41,6 +41,7 @@
     }
 
     void initialize() {
+        mLastVisibleRowIndex = -1;
         int i = mAdapter.size() - 1;
         while (i >= 0) {
             Row item = (Row) mAdapter.get(i);
@@ -123,7 +124,7 @@
             int totalItems = lastVisibleRowIndex - mLastVisibleRowIndex;
             if (totalItems > 0) {
                 onEventFired(ON_ITEM_RANGE_REMOVED,
-                        Math.min(lastVisibleRowIndex + 1, positionStart),
+                        Math.min(mLastVisibleRowIndex + 1, positionStart),
                         totalItems);
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
index 0459ab6..1baffb4 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
@@ -22,8 +22,8 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
-import android.app.Activity;
 import android.app.Fragment;
+import android.content.Context;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v17.leanback.R;
@@ -267,8 +267,9 @@
         mLogoView = (ImageView) view.findViewById(R.id.logo);
         mTitleView = (TextView) view.findViewById(R.id.title);
         mDescriptionView = (TextView) view.findViewById(R.id.description);
+        final Context context = FragmentUtil.getContext(this);
         if (sSlideDistance == 0) {
-            sSlideDistance = (int) (SLIDE_DISTANCE * getActivity().getResources()
+            sSlideDistance = (int) (SLIDE_DISTANCE * context.getResources()
                     .getDisplayMetrics().scaledDensity);
         }
         if (savedInstanceState == null) {
@@ -312,20 +313,20 @@
     }
 
     private void resolveTheme() {
-        Activity activity = getActivity();
+        final Context context = FragmentUtil.getContext(this);
         int theme = onProvideTheme();
         if (theme == -1) {
             // Look up the onboardingTheme in the activity's currently specified theme. If it
             // exists, wrap the theme with its value.
             int resId = R.attr.onboardingTheme;
             TypedValue typedValue = new TypedValue();
-            boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
+            boolean found = context.getTheme().resolveAttribute(resId, typedValue, true);
             if (DEBUG) Log.v(TAG, "Found onboarding theme reference? " + found);
             if (found) {
-                mThemeWrapper = new ContextThemeWrapper(activity, typedValue.resourceId);
+                mThemeWrapper = new ContextThemeWrapper(context, typedValue.resourceId);
             }
         } else {
-            mThemeWrapper = new ContextThemeWrapper(activity, theme);
+            mThemeWrapper = new ContextThemeWrapper(context, theme);
         }
     }
 
@@ -366,13 +367,14 @@
     }
 
     boolean startLogoAnimation() {
+        final Context context = FragmentUtil.getContext(this);
         Animator animator = null;
         if (mLogoResourceId != 0) {
             mLogoView.setVisibility(View.VISIBLE);
             mLogoView.setImageResource(mLogoResourceId);
-            Animator inAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator inAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_logo_enter);
-            Animator outAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator outAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_logo_exit);
             outAnimator.setStartDelay(LOGO_SPLASH_PAUSE_DURATION_MS);
             AnimatorSet logoAnimator = new AnimatorSet();
@@ -386,7 +388,7 @@
             animator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    if (getActivity() != null) {
+                    if (context != null) {
                         startEnterAnimation();
                     }
                 }
@@ -411,7 +413,8 @@
     private void initializeViews(View container) {
         mLogoView.setVisibility(View.GONE);
         // Create custom views.
-        LayoutInflater inflater = getThemeInflater(LayoutInflater.from(getActivity()));
+        LayoutInflater inflater = getThemeInflater(LayoutInflater.from(
+                FragmentUtil.getContext(this)));
         ViewGroup backgroundContainer = (ViewGroup) container.findViewById(
                 R.id.background_container);
         View background = onCreateBackgroundView(inflater, backgroundContainer);
@@ -453,22 +456,23 @@
         mEnterTransitionFinished = true;
         initializeViews(getView());
         List<Animator> animators = new ArrayList<>();
-        Animator animator = AnimatorInflater.loadAnimator(getActivity(),
+        final Context context = FragmentUtil.getContext(this);
+        Animator animator = AnimatorInflater.loadAnimator(context,
                 R.animator.lb_onboarding_page_indicator_enter);
         animator.setTarget(getPageCount() <= 1 ? mStartButton : mPageIndicator);
         animators.add(animator);
         // Header title
-        View view = getActivity().findViewById(R.id.title);
+        View view = getView().findViewById(R.id.title);
         view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(getActivity(),
+        animator = AnimatorInflater.loadAnimator(context,
                 R.animator.lb_onboarding_title_enter);
         animator.setStartDelay(START_DELAY_TITLE_MS);
         animator.setTarget(view);
         animators.add(animator);
         // Header description
-        view = getActivity().findViewById(R.id.description);
+        view = getView().findViewById(R.id.description);
         view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(getActivity(),
+        animator = AnimatorInflater.loadAnimator(context,
                 R.animator.lb_onboarding_description_enter);
         animator.setStartDelay(START_DELAY_DESCRIPTION_MS);
         animator.setTarget(view);
@@ -610,10 +614,11 @@
             }
         });
 
+        final Context context = FragmentUtil.getContext(this);
         // Animator for switching between page indicator and button.
         if (getCurrentPageIndex() == getPageCount() - 1) {
             mStartButton.setVisibility(View.VISIBLE);
-            Animator navigatorFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator navigatorFadeOutAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_page_indicator_fade_out);
             navigatorFadeOutAnimator.setTarget(mPageIndicator);
             navigatorFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
@@ -623,17 +628,17 @@
                 }
             });
             animators.add(navigatorFadeOutAnimator);
-            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_start_button_fade_in);
             buttonFadeInAnimator.setTarget(mStartButton);
             animators.add(buttonFadeInAnimator);
         } else if (previousPage == getPageCount() - 1) {
             mPageIndicator.setVisibility(View.VISIBLE);
-            Animator navigatorFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator navigatorFadeInAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_page_indicator_fade_in);
             navigatorFadeInAnimator.setTarget(mPageIndicator);
             animators.add(navigatorFadeInAnimator);
-            Animator buttonFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator buttonFadeOutAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_start_button_fade_out);
             buttonFadeOutAnimator.setTarget(mStartButton);
             buttonFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
index 32163b0..8523a27 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
@@ -25,8 +25,8 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
-import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.Fragment;
+import android.content.Context;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v17.leanback.R;
@@ -270,8 +270,9 @@
         mLogoView = (ImageView) view.findViewById(R.id.logo);
         mTitleView = (TextView) view.findViewById(R.id.title);
         mDescriptionView = (TextView) view.findViewById(R.id.description);
+        final Context context = getContext();
         if (sSlideDistance == 0) {
-            sSlideDistance = (int) (SLIDE_DISTANCE * getActivity().getResources()
+            sSlideDistance = (int) (SLIDE_DISTANCE * context.getResources()
                     .getDisplayMetrics().scaledDensity);
         }
         if (savedInstanceState == null) {
@@ -315,20 +316,20 @@
     }
 
     private void resolveTheme() {
-        FragmentActivity activity = getActivity();
+        final Context context = getContext();
         int theme = onProvideTheme();
         if (theme == -1) {
             // Look up the onboardingTheme in the activity's currently specified theme. If it
             // exists, wrap the theme with its value.
             int resId = R.attr.onboardingTheme;
             TypedValue typedValue = new TypedValue();
-            boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
+            boolean found = context.getTheme().resolveAttribute(resId, typedValue, true);
             if (DEBUG) Log.v(TAG, "Found onboarding theme reference? " + found);
             if (found) {
-                mThemeWrapper = new ContextThemeWrapper(activity, typedValue.resourceId);
+                mThemeWrapper = new ContextThemeWrapper(context, typedValue.resourceId);
             }
         } else {
-            mThemeWrapper = new ContextThemeWrapper(activity, theme);
+            mThemeWrapper = new ContextThemeWrapper(context, theme);
         }
     }
 
@@ -369,13 +370,14 @@
     }
 
     boolean startLogoAnimation() {
+        final Context context = getContext();
         Animator animator = null;
         if (mLogoResourceId != 0) {
             mLogoView.setVisibility(View.VISIBLE);
             mLogoView.setImageResource(mLogoResourceId);
-            Animator inAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator inAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_logo_enter);
-            Animator outAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator outAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_logo_exit);
             outAnimator.setStartDelay(LOGO_SPLASH_PAUSE_DURATION_MS);
             AnimatorSet logoAnimator = new AnimatorSet();
@@ -389,7 +391,7 @@
             animator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    if (getActivity() != null) {
+                    if (context != null) {
                         startEnterAnimation();
                     }
                 }
@@ -414,7 +416,8 @@
     private void initializeViews(View container) {
         mLogoView.setVisibility(View.GONE);
         // Create custom views.
-        LayoutInflater inflater = getThemeInflater(LayoutInflater.from(getActivity()));
+        LayoutInflater inflater = getThemeInflater(LayoutInflater.from(
+                getContext()));
         ViewGroup backgroundContainer = (ViewGroup) container.findViewById(
                 R.id.background_container);
         View background = onCreateBackgroundView(inflater, backgroundContainer);
@@ -456,22 +459,23 @@
         mEnterTransitionFinished = true;
         initializeViews(getView());
         List<Animator> animators = new ArrayList<>();
-        Animator animator = AnimatorInflater.loadAnimator(getActivity(),
+        final Context context = getContext();
+        Animator animator = AnimatorInflater.loadAnimator(context,
                 R.animator.lb_onboarding_page_indicator_enter);
         animator.setTarget(getPageCount() <= 1 ? mStartButton : mPageIndicator);
         animators.add(animator);
         // Header title
-        View view = getActivity().findViewById(R.id.title);
+        View view = getView().findViewById(R.id.title);
         view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(getActivity(),
+        animator = AnimatorInflater.loadAnimator(context,
                 R.animator.lb_onboarding_title_enter);
         animator.setStartDelay(START_DELAY_TITLE_MS);
         animator.setTarget(view);
         animators.add(animator);
         // Header description
-        view = getActivity().findViewById(R.id.description);
+        view = getView().findViewById(R.id.description);
         view.setAlpha(0);
-        animator = AnimatorInflater.loadAnimator(getActivity(),
+        animator = AnimatorInflater.loadAnimator(context,
                 R.animator.lb_onboarding_description_enter);
         animator.setStartDelay(START_DELAY_DESCRIPTION_MS);
         animator.setTarget(view);
@@ -613,10 +617,11 @@
             }
         });
 
+        final Context context = getContext();
         // Animator for switching between page indicator and button.
         if (getCurrentPageIndex() == getPageCount() - 1) {
             mStartButton.setVisibility(View.VISIBLE);
-            Animator navigatorFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator navigatorFadeOutAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_page_indicator_fade_out);
             navigatorFadeOutAnimator.setTarget(mPageIndicator);
             navigatorFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
@@ -626,17 +631,17 @@
                 }
             });
             animators.add(navigatorFadeOutAnimator);
-            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator buttonFadeInAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_start_button_fade_in);
             buttonFadeInAnimator.setTarget(mStartButton);
             animators.add(buttonFadeInAnimator);
         } else if (previousPage == getPageCount() - 1) {
             mPageIndicator.setVisibility(View.VISIBLE);
-            Animator navigatorFadeInAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator navigatorFadeInAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_page_indicator_fade_in);
             navigatorFadeInAnimator.setTarget(mPageIndicator);
             animators.add(navigatorFadeInAnimator);
-            Animator buttonFadeOutAnimator = AnimatorInflater.loadAnimator(getActivity(),
+            Animator buttonFadeOutAnimator = AnimatorInflater.loadAnimator(context,
                     R.animator.lb_onboarding_start_button_fade_out);
             buttonFadeOutAnimator.setTarget(mStartButton);
             buttonFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
index 02a0257..1058ab1 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
@@ -452,11 +452,12 @@
             }
         };
 
-        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
+        Context context = FragmentUtil.getContext(this);
+        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
         mBgFadeInAnimator.addUpdateListener(listener);
         mBgFadeInAnimator.addListener(mFadeListener);
 
-        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
         mBgFadeOutAnimator.addUpdateListener(listener);
         mBgFadeOutAnimator.addListener(mFadeListener);
     }
@@ -498,14 +499,14 @@
             }
         };
 
-        mControlRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = FragmentUtil.getContext(this);
+        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mControlRowFadeInAnimator.addUpdateListener(updateListener);
         mControlRowFadeInAnimator.addListener(listener);
         mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mControlRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_controls_fade_out);
         mControlRowFadeOutAnimator.addUpdateListener(updateListener);
         mControlRowFadeOutAnimator.addListener(listener);
         mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
@@ -543,14 +544,13 @@
             }
         };
 
-        mOtherRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = FragmentUtil.getContext(this);
+        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mOtherRowFadeInAnimator.addListener(listener);
         mOtherRowFadeInAnimator.addUpdateListener(updateListener);
         mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mOtherRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
         mOtherRowFadeOutAnimator.addListener(listener);
         mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
         mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
@@ -808,7 +808,6 @@
     /**
      * This listener is called every time there is a selection in {@link RowsFragment}. This can
      * be used by users to take additional actions such as animations.
-     * @hide
      */
     public void setOnItemViewSelectedListener(final BaseOnItemViewSelectedListener listener) {
         mExternalItemSelectedListener = listener;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
index 33e35eb..3b8cfd3 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
@@ -433,11 +433,12 @@
             }
         };
 
-        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
+        Context context = FragmentUtil.getContext(this);
+        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
         mBgFadeInAnimator.addUpdateListener(listener);
         mBgFadeInAnimator.addListener(mFadeListener);
 
-        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
         mBgFadeOutAnimator.addUpdateListener(listener);
         mBgFadeOutAnimator.addListener(mFadeListener);
     }
@@ -479,14 +480,14 @@
             }
         };
 
-        mControlRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = FragmentUtil.getContext(this);
+        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mControlRowFadeInAnimator.addUpdateListener(updateListener);
         mControlRowFadeInAnimator.addListener(listener);
         mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mControlRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_controls_fade_out);
         mControlRowFadeOutAnimator.addUpdateListener(updateListener);
         mControlRowFadeOutAnimator.addListener(listener);
         mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
@@ -524,14 +525,13 @@
             }
         };
 
-        mOtherRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = FragmentUtil.getContext(this);
+        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mOtherRowFadeInAnimator.addListener(listener);
         mOtherRowFadeInAnimator.addUpdateListener(updateListener);
         mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mOtherRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
         mOtherRowFadeOutAnimator.addListener(listener);
         mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
         mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
@@ -557,13 +557,14 @@
             }
         };
 
-        mDescriptionFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_description_fade_in);
+        Context context = FragmentUtil.getContext(this);
+        mDescriptionFadeInAnimator = loadAnimator(context,
+                R.animator.lb_playback_description_fade_in);
         mDescriptionFadeInAnimator.addUpdateListener(listener);
         mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mDescriptionFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_description_fade_out);
+        mDescriptionFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_description_fade_out);
         mDescriptionFadeOutAnimator.addUpdateListener(listener);
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
index d41d65f..b58a2ad 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
@@ -436,11 +436,12 @@
             }
         };
 
-        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
+        Context context = getContext();
+        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
         mBgFadeInAnimator.addUpdateListener(listener);
         mBgFadeInAnimator.addListener(mFadeListener);
 
-        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
         mBgFadeOutAnimator.addUpdateListener(listener);
         mBgFadeOutAnimator.addListener(mFadeListener);
     }
@@ -482,14 +483,14 @@
             }
         };
 
-        mControlRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = getContext();
+        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mControlRowFadeInAnimator.addUpdateListener(updateListener);
         mControlRowFadeInAnimator.addListener(listener);
         mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mControlRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_controls_fade_out);
         mControlRowFadeOutAnimator.addUpdateListener(updateListener);
         mControlRowFadeOutAnimator.addListener(listener);
         mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
@@ -527,14 +528,13 @@
             }
         };
 
-        mOtherRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = getContext();
+        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mOtherRowFadeInAnimator.addListener(listener);
         mOtherRowFadeInAnimator.addUpdateListener(updateListener);
         mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mOtherRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
         mOtherRowFadeOutAnimator.addListener(listener);
         mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
         mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
@@ -560,13 +560,14 @@
             }
         };
 
-        mDescriptionFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_description_fade_in);
+        Context context = getContext();
+        mDescriptionFadeInAnimator = loadAnimator(context,
+                R.animator.lb_playback_description_fade_in);
         mDescriptionFadeInAnimator.addUpdateListener(listener);
         mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mDescriptionFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_description_fade_out);
+        mDescriptionFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_description_fade_out);
         mDescriptionFadeOutAnimator.addUpdateListener(listener);
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
index 07701f9..b812004 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
@@ -455,11 +455,12 @@
             }
         };
 
-        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
+        Context context = getContext();
+        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
         mBgFadeInAnimator.addUpdateListener(listener);
         mBgFadeInAnimator.addListener(mFadeListener);
 
-        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
         mBgFadeOutAnimator.addUpdateListener(listener);
         mBgFadeOutAnimator.addListener(mFadeListener);
     }
@@ -501,14 +502,14 @@
             }
         };
 
-        mControlRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = getContext();
+        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mControlRowFadeInAnimator.addUpdateListener(updateListener);
         mControlRowFadeInAnimator.addListener(listener);
         mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mControlRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_controls_fade_out);
         mControlRowFadeOutAnimator.addUpdateListener(updateListener);
         mControlRowFadeOutAnimator.addListener(listener);
         mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
@@ -546,14 +547,13 @@
             }
         };
 
-        mOtherRowFadeInAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_in);
+        Context context = getContext();
+        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
         mOtherRowFadeInAnimator.addListener(listener);
         mOtherRowFadeInAnimator.addUpdateListener(updateListener);
         mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
 
-        mOtherRowFadeOutAnimator = loadAnimator(
-                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
         mOtherRowFadeOutAnimator.addListener(listener);
         mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
         mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
@@ -811,7 +811,6 @@
     /**
      * This listener is called every time there is a selection in {@link RowsSupportFragment}. This can
      * be used by users to take additional actions such as animations.
-     * @hide
      */
     public void setOnItemViewSelectedListener(final BaseOnItemViewSelectedListener listener) {
         mExternalItemSelectedListener = listener;
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 93886f9..d2b9bb1 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -391,7 +391,8 @@
         super.onResume();
         mIsPaused = false;
         if (mSpeechRecognitionCallback == null && null == mSpeechRecognizer) {
-            mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(getActivity());
+            mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(
+                    FragmentUtil.getContext(this));
             mSearchBar.setSpeechRecognizer(mSpeechRecognizer);
         }
         if (mPendingStartRecognitionWhenPaused) {
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 c8a058d..b870d79 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
@@ -394,7 +394,8 @@
         super.onResume();
         mIsPaused = false;
         if (mSpeechRecognitionCallback == null && null == mSpeechRecognizer) {
-            mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(getActivity());
+            mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(
+                    getContext());
             mSearchBar.setSpeechRecognizer(mSpeechRecognizer);
         }
         if (mPendingStartRecognitionWhenPaused) {
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 b8f3df2..cfa27df 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
@@ -13,9 +13,11 @@
  */
 package android.support.v17.leanback.app;
 
+import android.os.Bundle;
 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.ObjectAdapter;
 import android.support.v17.leanback.widget.OnChildLaidOutListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
@@ -23,8 +25,6 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.VerticalGridPresenter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -223,7 +223,7 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(FragmentUtil.getContext(this),
                 R.transition.lb_vertical_grid_entrance_transition);
     }
 
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 2a87f10..55e079d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
@@ -16,9 +16,11 @@
  */
 package android.support.v17.leanback.app;
 
+import android.os.Bundle;
 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.ObjectAdapter;
 import android.support.v17.leanback.widget.OnChildLaidOutListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
@@ -26,8 +28,6 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.VerticalGridPresenter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -226,7 +226,7 @@
 
     @Override
     protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getActivity(),
+        return TransitionHelper.loadTransition(getContext(),
                 R.transition.lb_vertical_grid_entrance_transition);
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VideoFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VideoFragment.java
index fa9989e..9906813 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VideoFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VideoFragment.java
@@ -39,7 +39,7 @@
     public View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
-        mVideoSurface = (SurfaceView) getActivity().getLayoutInflater().inflate(
+        mVideoSurface = (SurfaceView) LayoutInflater.from(FragmentUtil.getContext(this)).inflate(
                 R.layout.lb_video_surface, root, false);
         root.addView(mVideoSurface, 0);
         mVideoSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VideoSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VideoSupportFragment.java
index 0f76e6e..29f1faf 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VideoSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VideoSupportFragment.java
@@ -42,7 +42,7 @@
     public View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
-        mVideoSurface = (SurfaceView) getActivity().getLayoutInflater().inflate(
+        mVideoSurface = (SurfaceView) LayoutInflater.from(getContext()).inflate(
                 R.layout.lb_video_surface, root, false);
         root.addView(mVideoSurface, 0);
         mVideoSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Grid.java b/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
index 64d151f..eb09225 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
@@ -13,7 +13,10 @@
  */
 package android.support.v17.leanback.widget;
 
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.util.CircularIntArray;
+import android.support.v7.widget.RecyclerView;
 
 import java.io.PrintWriter;
 
@@ -259,7 +262,7 @@
      * Finds the largest or smallest row min edge of visible items,
      * the row index is returned in indices[0], the item index is returned in indices[1].
      */
-    public final int findRowMin(boolean findLarge, int[] indices) {
+    public final int findRowMin(boolean findLarge, @Nullable int[] indices) {
         return findRowMin(findLarge, mReversedFlow ? mLastVisibleIndex : mFirstVisibleIndex,
                 indices);
     }
@@ -274,7 +277,7 @@
      * Finds the largest or smallest row max edge of visible items, the row index is returned in
      * indices[0], the item index is returned in indices[1].
      */
-    public final int findRowMax(boolean findLarge, int[] indices) {
+    public final int findRowMax(boolean findLarge, @Nullable int[] indices) {
         return findRowMax(findLarge, mReversedFlow ? mFirstVisibleIndex : mLastVisibleIndex,
                 indices);
     }
@@ -422,5 +425,12 @@
         }
     }
 
+    /**
+     * Queries items adjacent to the viewport (in the direction of da) into the prefetch registry.
+     */
+    public void collectAdjacentPrefetchPositions(int fromLimit, int da,
+            @NonNull RecyclerView.LayoutManager.LayoutPrefetchRegistry layoutPrefetchRegistry) {
+    }
+
     public abstract void debugPrint(PrintWriter pw);
 }
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 580f01b..a2f99e2 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -2154,6 +2154,26 @@
         return dy;
     }
 
+    @Override
+    public void collectAdjacentPrefetchPositions(int dx, int dy, State state,
+            LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        try {
+            saveContext(null, state);
+            int da = (mOrientation == HORIZONTAL) ? dx : dy;
+            if (getChildCount() == 0 || da == 0) {
+                // can't support this scroll, so don't bother prefetching
+                return;
+            }
+
+            int fromLimit = da < 0
+                    ? -mExtraLayoutSpace
+                    : mSizePrimary + mExtraLayoutSpace;
+            mGrid.collectAdjacentPrefetchPositions(fromLimit, da, layoutPrefetchRegistry);
+        } finally {
+            leaveContext();
+        }
+    }
+
     void updateScrollMax() {
         int highVisiblePos = (!mReverseFlowPrimary) ? mGrid.getLastVisibleIndex()
                 : mGrid.getFirstVisibleIndex();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java b/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
index 0300c6f..04a384a 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
@@ -13,7 +13,9 @@
  */
 package android.support.v17.leanback.widget;
 
+import android.support.annotation.NonNull;
 import android.support.v4.util.CircularIntArray;
+import android.support.v7.widget.RecyclerView;
 
 import java.io.PrintWriter;
 
@@ -131,6 +133,36 @@
     }
 
     @Override
+    public void collectAdjacentPrefetchPositions(int fromLimit, int da,
+        @NonNull RecyclerView.LayoutManager.LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        int indexToPrefetch;
+        int nearestEdge;
+        if (mReversedFlow ? da > 0 : da < 0) {
+            // prefetch next prepend, lower index number
+            if (getFirstVisibleIndex() == 0) {
+                return; // no remaining items to prefetch
+            }
+
+            indexToPrefetch = getStartIndexForPrepend();
+            nearestEdge = mProvider.getEdge(mFirstVisibleIndex)
+                    + (mReversedFlow ? mSpacing : -mSpacing);
+        } else {
+            // prefetch next append, higher index number
+            if (getLastVisibleIndex() == mProvider.getCount() - 1) {
+                return; // no remaining items to prefetch
+            }
+
+            indexToPrefetch = getStartIndexForAppend();
+            int itemSizeWithSpace = mProvider.getSize(mLastVisibleIndex) + mSpacing;
+            nearestEdge = mProvider.getEdge(mLastVisibleIndex)
+                    + (mReversedFlow ? -itemSizeWithSpace : itemSizeWithSpace);
+        }
+
+        int distance = Math.abs(nearestEdge - fromLimit);
+        layoutPrefetchRegistry.addPosition(indexToPrefetch, distance);
+    }
+
+    @Override
     public final CircularIntArray[] getItemPositionsInRows(int startPos, int endPos) {
         // all items are on the same row:
         mTmpItemPositionsInRows[0].clear();
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
index b7cb4e8..0b40920 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
@@ -197,6 +197,48 @@
     }
 
     @Test
+    public void adapterSize_rowsRemoveAll() {
+        ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenterSelector);
+        adapter.add(new SectionRow("section 1"));
+        for (int i = 0; i < 4; i++) {
+            HeaderItem headerItem = new HeaderItem(i, "header "+i);
+            adapter.add(new ListRow(headerItem, createListRowAdapter()));
+        }
+
+        ListRowDataAdapter listRowDataAdapter = new ListRowDataAdapter(adapter);
+        assertEquals(5, listRowDataAdapter.size());
+
+        adapter.clear();
+        assertEquals(0, listRowDataAdapter.size());
+
+        HeaderItem headerItem = new HeaderItem(10, "header "+10);
+        adapter.add(new ListRow(headerItem, createListRowAdapter()));
+        assertEquals(1, listRowDataAdapter.size());
+    }
+
+    @Test
+    public void changeRemove_revealInvisibleItems() {
+        ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenterSelector);
+        for (int i = 0; i < 4; i++) {
+            HeaderItem headerItem = new HeaderItem(i, "header "+i);
+            adapter.add(new ListRow(headerItem, createListRowAdapter()));
+        }
+        adapter.add(new SectionRow("section"));
+        for (int i = 4; i < 8; i++) {
+            HeaderItem headerItem = new HeaderItem(i, "header "+i);
+            adapter.add(new ListRow(headerItem, createListRowAdapter()));
+        }
+
+        ListRowDataAdapter listRowDataAdapter = new ListRowDataAdapter(adapter);
+        assertEquals(9, listRowDataAdapter.size());
+
+        listRowDataAdapter.registerObserver(dataObserver);
+        adapter.removeItems(5, 4);
+        verify(dataObserver, times(1)).onItemRangeRemoved(4, 5);
+        assertEquals(4, listRowDataAdapter.size());
+    }
+
+    @Test
     public void adapterSize_rowsRemoved() {
         int itemCount = 4;
         ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenterSelector);
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetPrefetchTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetPrefetchTest.java
new file mode 100644
index 0000000..c50aa67
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetPrefetchTest.java
@@ -0,0 +1,177 @@
+package android.support.v17.leanback.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GridWidgetPrefetchTest {
+
+    private Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+
+    private void layout(View view, int width, int height) {
+        view.measure(
+                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+        view.layout(0, 0, width, height);
+    }
+
+    public void validatePrefetch(BaseGridView gridView, int scrollX, int scrollY,
+            Integer[]... positionData) {
+        // duplicates logic in support.v7.widget.CacheUtils#verifyPositionsPrefetched
+        RecyclerView.State state = mock(RecyclerView.State.class);
+        when(state.getItemCount()).thenReturn(gridView.getAdapter().getItemCount());
+        RecyclerView.LayoutManager.LayoutPrefetchRegistry registry
+                = mock(RecyclerView.LayoutManager.LayoutPrefetchRegistry.class);
+
+        gridView.getLayoutManager().collectAdjacentPrefetchPositions(scrollX, scrollY,
+                state, registry);
+
+        verify(registry, times(positionData.length)).addPosition(anyInt(), anyInt());
+        for (Integer[] aPositionData : positionData) {
+            verify(registry).addPosition(aPositionData[0], aPositionData[1]);
+        }
+    }
+
+    private RecyclerView.Adapter createBoxAdapter() {
+        return new RecyclerView.Adapter() {
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+                View view = new View(getContext());
+                view.setMinimumWidth(100);
+                view.setMinimumHeight(100);
+                return new RecyclerView.ViewHolder(view) {};
+            }
+
+            @Override
+            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+                // noop
+            }
+
+            @Override
+            public int getItemCount() {
+                return 100;
+            }
+        };
+    }
+
+    @Test
+    public void prefetch() {
+        HorizontalGridView gridView = new HorizontalGridView(getContext());
+        gridView.setNumRows(1);
+        gridView.setRowHeight(100);
+        gridView.setAdapter(createBoxAdapter());
+
+        layout(gridView, 150, 100);
+
+        // validate 2 children in viewport
+        assertEquals(2, gridView.getChildCount());
+        assertEquals(0, gridView.getLayoutManager().findViewByPosition(0).getLeft());
+        assertEquals(100, gridView.getLayoutManager().findViewByPosition(1).getLeft());
+
+        validatePrefetch(gridView, -50, 0); // no view to left
+        validatePrefetch(gridView, 50, 0, new Integer[] {2, 50}); // next view 50 pixels to right
+
+        // scroll to position 5, and layout
+        gridView.scrollToPosition(5);
+        layout(gridView, 150, 100);
+
+        /* Visual representation, each number column represents 25 pixels:
+         *              |           |
+         * ... 3 3 4 4 4|4 5 5 5 5 6|6 6 6 7 7 ...
+         *              |           |
+         */
+
+        // validate the 3 children in the viewport, and their positions
+        assertEquals(3, gridView.getChildCount());
+        assertNotNull(gridView.getLayoutManager().findViewByPosition(4));
+        assertNotNull(gridView.getLayoutManager().findViewByPosition(5));
+        assertNotNull(gridView.getLayoutManager().findViewByPosition(6));
+        assertEquals(-75, gridView.getLayoutManager().findViewByPosition(4).getLeft());
+        assertEquals(25, gridView.getLayoutManager().findViewByPosition(5).getLeft());
+        assertEquals(125, gridView.getLayoutManager().findViewByPosition(6).getLeft());
+
+        // next views are 75 pixels to right and left:
+        validatePrefetch(gridView, -50, 0, new Integer[] {3, 75});
+        validatePrefetch(gridView, 50, 0, new Integer[] {7, 75});
+
+        // no views returned for vertical prefetch:
+        validatePrefetch(gridView, 0, 10);
+        validatePrefetch(gridView, 0, -10);
+
+        // test minor offset
+        gridView.scrollBy(5, 0);
+        validatePrefetch(gridView, -50, 0, new Integer[] {3, 80});
+        validatePrefetch(gridView, 50, 0, new Integer[] {7, 70});
+    }
+
+    @Test
+    public void prefetchRtl() {
+        HorizontalGridView gridView = new HorizontalGridView(getContext());
+        gridView.setNumRows(1);
+        gridView.setRowHeight(100);
+        gridView.setAdapter(createBoxAdapter());
+        gridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+
+        layout(gridView, 150, 100);
+
+        // validate 2 children in viewport
+        assertEquals(2, gridView.getChildCount());
+        assertEquals(50, gridView.getLayoutManager().findViewByPosition(0).getLeft());
+        assertEquals(-50, gridView.getLayoutManager().findViewByPosition(1).getLeft());
+
+        validatePrefetch(gridView, 50, 0); // no view to right
+        validatePrefetch(gridView, -10, 0, new Integer[] {2, 50}); // next view 50 pixels to right
+
+
+        // scroll to position 5, and layout
+        gridView.scrollToPosition(5);
+        layout(gridView, 150, 100);
+
+
+        /* Visual representation, each number column represents 25 pixels:
+         *              |           |
+         * ... 7 7 6 6 6|6 5 5 5 5 4|4 4 4 3 3 ...
+         *              |           |
+         */
+        // validate 3 children in the viewport
+        assertEquals(3, gridView.getChildCount());
+        assertNotNull(gridView.getLayoutManager().findViewByPosition(6));
+        assertNotNull(gridView.getLayoutManager().findViewByPosition(5));
+        assertNotNull(gridView.getLayoutManager().findViewByPosition(4));
+        assertEquals(-75, gridView.getLayoutManager().findViewByPosition(6).getLeft());
+        assertEquals(25, gridView.getLayoutManager().findViewByPosition(5).getLeft());
+        assertEquals(125, gridView.getLayoutManager().findViewByPosition(4).getLeft());
+
+        // next views are 75 pixels to right and left:
+        validatePrefetch(gridView, 50, 0, new Integer[] {3, 75});
+        validatePrefetch(gridView, -50, 0, new Integer[] {7, 75});
+
+        // no views returned for vertical prefetch:
+        validatePrefetch(gridView, 0, 10);
+        validatePrefetch(gridView, 0, -10);
+
+        // test minor offset
+        gridView.scrollBy(-5, 0);
+        validatePrefetch(gridView, 50, 0, new Integer[] {3, 80});
+        validatePrefetch(gridView, -50, 0, new Integer[] {7, 70});
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java
index 82261d1..373cb81 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java
@@ -16,9 +16,14 @@
 package android.support.v17.leanback.widget;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.RecyclerView;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,7 +35,7 @@
 @RunWith(AndroidJUnit4.class)
 public class SingleRowTest extends GridTest {
 
-    SingleRow mSingleRow;
+    private SingleRow mSingleRow;
 
     @Test
     public void testAppendPrependRemove() {
@@ -161,4 +166,97 @@
         mSingleRow.prependVisibleItems(0);
         assertEquals(dump(mSingleRow) + " Should not prepend 0", 1, mSingleRow.mFirstVisibleIndex);
     }
+
+    public void validatePrefetch(int fromLimit, int delta, Integer[]... positionData) {
+        // duplicates logic in support.v7.widget.CacheUtils#verifyPositionsPrefetched
+        RecyclerView.LayoutManager.LayoutPrefetchRegistry registry
+                = mock(RecyclerView.LayoutManager.LayoutPrefetchRegistry.class);
+        mSingleRow.collectAdjacentPrefetchPositions(fromLimit, delta, registry);
+
+        verify(registry, times(positionData.length)).addPosition(anyInt(), anyInt());
+        for (Integer[] aPositionData : positionData) {
+            verify(registry).addPosition(aPositionData[0], aPositionData[1]);
+        }
+    }
+
+    @Test
+    public void testPrefetchBounds() {
+        mProvider = new Provider(new int[]{100, 100});
+
+        mSingleRow = new SingleRow();
+        mSingleRow.setSpacing(20);
+        mSingleRow.setProvider(mProvider);
+        mSingleRow.appendVisibleItems(150);
+
+        validatePrefetch(0, -10);
+        validatePrefetch(-150, 10);
+    }
+
+    @Test
+    public void testPrefetchBoundsReversed() {
+        mProvider = new Provider(new int[]{100, 100});
+
+        mSingleRow = new SingleRow();
+        mSingleRow.setSpacing(20);
+        mSingleRow.setProvider(mProvider);
+        mSingleRow.setReversedFlow(true);
+        mSingleRow.appendVisibleItems(-150);
+
+        validatePrefetch(0, -10);
+        validatePrefetch(150, 10);
+    }
+
+    @Test
+    public void testPrefetchItems() {
+        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
+
+        mSingleRow = new SingleRow();
+        mSingleRow.setSpacing(20);
+        mSingleRow.setProvider(mProvider);
+        mSingleRow.appendVisibleItems(200);
+
+        // next item, 2, is 0 pixels away
+        validatePrefetch(200, 10, new Integer[] {2, 0});
+
+        // nothing above
+        validatePrefetch(0, -10);
+
+        mProvider.scroll(90);
+        mSingleRow.removeInvisibleItemsAtFront(Integer.MAX_VALUE, 0);
+        mSingleRow.appendVisibleItems(200);
+
+        // next item, 4, is 80 pixels away
+        validatePrefetch(200, 10, new Integer[] {4, 80});
+
+        // next item, 0, is 10 pixels away
+        validatePrefetch(0, -10, new Integer[] {0, 10});
+    }
+
+    @Test
+    public void testPrefetchItemsReversed() {
+        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
+
+        mSingleRow = new SingleRow();
+        mSingleRow.setSpacing(20);
+        mSingleRow.setProvider(mProvider);
+        mSingleRow.setReversedFlow(true);
+        mSingleRow.appendVisibleItems(-200);
+
+        // next item, 2, is 0 pixels away
+        validatePrefetch(-200, -10, new Integer[] {2, 0});
+
+        // nothing above
+        validatePrefetch(0, 10);
+
+        mProvider.scroll(-90);
+        mSingleRow.removeInvisibleItemsAtFront(Integer.MAX_VALUE, 0);
+        mSingleRow.appendVisibleItems(-200);
+
+        // next item, 4, is 80 pixels away
+        validatePrefetch(-200, -10, new Integer[] {4, 80});
+
+        // one above, 0, is 10 pixels away
+        validatePrefetch(0, 10, new Integer[] {0, 10});
+
+    }
 }
\ No newline at end of file
diff --git a/v17/preference-leanback/Android.mk b/v17/preference-leanback/Android.mk
index 263d334..8c0488f 100644
--- a/v17/preference-leanback/Android.mk
+++ b/v17/preference-leanback/Android.mk
@@ -35,6 +35,7 @@
     $(call all-java-files-under,api21) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v17-leanback \
     android-support-v14-preference \
diff --git a/v17/preference-leanback/AndroidManifest-make.xml b/v17/preference-leanback/AndroidManifest-make.xml
new file mode 100644
index 0000000..e2cfe35
--- /dev/null
+++ b/v17/preference-leanback/AndroidManifest-make.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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.support.v17.preference"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-sdk android:minSdkVersion="17" />
+    <application />
+</manifest>
diff --git a/v17/preference-leanback/build.gradle b/v17/preference-leanback/build.gradle
index 9bfd0f3..e58fa8b 100644
--- a/v17/preference-leanback/build.gradle
+++ b/v17/preference-leanback/build.gradle
@@ -36,28 +36,11 @@
     }
     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);
 }
 
diff --git a/v4/Android.mk b/v4/Android.mk
index a9c9145..c7e35aa 100644
--- a/v4/Android.mk
+++ b/v4/Android.mk
@@ -35,6 +35,7 @@
     android-support-fragment \
     android-support-annotations
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/v4/AndroidManifest-make.xml b/v4/AndroidManifest-make.xml
new file mode 100644
index 0000000..d76c581
--- /dev/null
+++ b/v4/AndroidManifest-make.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.support.v4">
+    <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.v4"/>
+    <application />
+</manifest>
diff --git a/v4/AndroidManifest.xml b/v4/AndroidManifest.xml
index d76c581..cecc743 100644
--- a/v4/AndroidManifest.xml
+++ b/v4/AndroidManifest.xml
@@ -17,5 +17,6 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v4">
     <uses-sdk android:minSdkVersion="9" tools:overrideLibrary="android.support.v4"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v4/build.gradle b/v4/build.gradle
index f0226e3..f226a87 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -1,6 +1,6 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'support-v4'
+
 dependencies {
     compile project(':support-compat')
     compile project(':support-media-compat')
diff --git a/v7/appcompat/Android.mk b/v7/appcompat/Android.mk
index 93baa95..3c5b44c 100644
--- a/v7/appcompat/Android.mk
+++ b/v7/appcompat/Android.mk
@@ -28,6 +28,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-vectordrawable \
     android-support-animatedvectordrawable
diff --git a/v7/appcompat/AndroidManifest-make.xml b/v7/appcompat/AndroidManifest-make.xml
new file mode 100644
index 0000000..99b77ee
--- /dev/null
+++ b/v7/appcompat/AndroidManifest-make.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.v7.appcompat">
+    <uses-sdk android:minSdkVersion="9"
+              tools:overrideLibrary="android.support.graphics.drawable.animated"/>
+    <application/>
+</manifest>
diff --git a/v7/appcompat/AndroidManifest.xml b/v7/appcompat/AndroidManifest.xml
index 99b77ee..d5858d1 100644
--- a/v7/appcompat/AndroidManifest.xml
+++ b/v7/appcompat/AndroidManifest.xml
@@ -18,5 +18,6 @@
           package="android.support.v7.appcompat">
     <uses-sdk android:minSdkVersion="9"
               tools:overrideLibrary="android.support.graphics.drawable.animated"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application/>
 </manifest>
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index aa62632..4935085 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'appcompat-v7'
 
 dependencies {
@@ -61,28 +60,11 @@
     }
     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);
 }
 
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 b3babb2..118ce2b 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,14 +14,17 @@
      limitations under the License.
 -->
 
-<ImageView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:id="@+id/action_mode_close_button"
-        android:contentDescription="@string/abc_action_mode_done"
-        android:focusable="true"
-        android:clickable="true"
-        app:srcCompat="?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"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/action_mode_close_button"
+    style="?attr/actionModeCloseButtonStyle"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:layout_marginEnd="16dip"
+    android:layout_marginRight="16dip"
+    android:clickable="true"
+    android:contentDescription="@string/abc_action_mode_done"
+    android:focusable="true"
+    android:paddingLeft="8dp"
+    android:paddingStart="8dp"
+    app:srcCompat="?attr/actionModeCloseDrawable" />
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v11/themes_base.xml b/v7/appcompat/res/values-v11/themes_base.xml
index d38ef32..11ef632 100644
--- a/v7/appcompat/res/values-v11/themes_base.xml
+++ b/v7/appcompat/res/values-v11/themes_base.xml
@@ -32,6 +32,7 @@
 
         <item name="android:buttonBarStyle">?attr/buttonBarStyle</item>
         <item name="android:buttonBarButtonStyle">?attr/buttonBarButtonStyle</item>
+        <item name="android:borderlessButtonStyle">?attr/borderlessButtonStyle</item>
 
         <!-- Window colors -->
         <item name="android:colorForeground">@color/foreground_material_dark</item>
@@ -86,6 +87,7 @@
 
         <item name="android:buttonBarStyle">?attr/buttonBarStyle</item>
         <item name="android:buttonBarButtonStyle">?attr/buttonBarButtonStyle</item>
+        <item name="android:borderlessButtonStyle">?attr/borderlessButtonStyle</item>
 
         <!-- Window colors -->
         <item name="android:colorForeground">@color/foreground_material_light</item>
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
index b52c0ba..c5839f9 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
@@ -92,11 +92,15 @@
 import android.widget.PopupWindow;
 import android.widget.TextView;
 
+import org.xmlpull.v1.XmlPullParser;
+
 @RequiresApi(9)
 @TargetApi(9)
 class AppCompatDelegateImplV9 extends AppCompatDelegateImplBase
         implements MenuBuilder.Callback, LayoutInflaterFactory {
 
+    private static final boolean IS_PRE_LOLLIPOP = Build.VERSION.SDK_INT < 21;
+
     private DecorContentParent mDecorContentParent;
     private ActionMenuPresenterCallback mActionMenuPresenterCallback;
     private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
@@ -1009,17 +1013,21 @@
     @Override
     public View createView(View parent, final String name, @NonNull Context context,
             @NonNull AttributeSet attrs) {
-        final boolean isPre21 = Build.VERSION.SDK_INT < 21;
-
         if (mAppCompatViewInflater == null) {
             mAppCompatViewInflater = new AppCompatViewInflater();
         }
 
-        // We only want the View to inherit its context if we're running pre-v21
-        final boolean inheritContext = isPre21 && shouldInheritContext((ViewParent) parent);
+        boolean inheritContext = false;
+        if (IS_PRE_LOLLIPOP) {
+            inheritContext = (attrs instanceof XmlPullParser)
+                    // If we have a XmlPullParser, we can detect where we are in the layout
+                    ? ((XmlPullParser) attrs).getDepth() > 1
+                    // Otherwise we have to use the old heuristic
+                    : shouldInheritContext((ViewParent) parent);
+        }
 
         return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,
-                isPre21, /* Only read android:theme pre-L (L+ handles this anyway) */
+                IS_PRE_LOLLIPOP, /* Only read android:theme pre-L (L+ handles this anyway) */
                 true, /* Read read app:theme as a fallback at all times for legacy reasons */
                 VectorEnabledTintResources.shouldBeUsed() /* Only tint wrap the context if enabled */
         );
@@ -1068,8 +1076,7 @@
      * From {@link android.support.v4.view.LayoutInflaterFactory}
      */
     @Override
-    public final View onCreateView(View parent, String name,
-            Context context, AttributeSet attrs) {
+    public final View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
         // First let the Activity's Factory try and inflate the view
         final View view = callActivityOnCreateView(parent, name, context, attrs);
         if (view != null) {
diff --git a/v7/appcompat/tests/res/layout/layout_children.xml b/v7/appcompat/tests/res/layout/layout_children.xml
new file mode 100644
index 0000000..a61175a
--- /dev/null
+++ b/v7/appcompat/tests/res/layout/layout_children.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:orientation="vertical">
+
+    <TextView android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="Test"/>
+
+    <TextView android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="Test"/>
+
+    <TextView android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="Test"/>
+
+    <TextView android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="Test"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java
index f7004b3..0502ad4 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java
@@ -37,9 +37,11 @@
 import android.support.v7.widget.AppCompatRatingBar;
 import android.support.v7.widget.AppCompatSpinner;
 import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.LinearLayout;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -82,13 +84,28 @@
         LayoutInflater inflater = LayoutInflater.from(getActivity());
         final ViewGroup root = (ViewGroup) inflater.inflate(
                 R.layout.layout_android_theme_children, null);
-
         assertThemedContext(root);
+    }
 
-        for (int i = 0; i < root.getChildCount(); i++) {
-            final View child = root.getChildAt(i);
-            assertThemedContext(child);
-        }
+    @UiThreadTest
+    @Test
+    @SmallTest
+    public void testThemedInflationWithUnattachedParent() {
+        final Context activity = getActivity();
+
+        // Create a parent but not attached
+        final LinearLayout parent = new LinearLayout(activity);
+
+        // Now create a LayoutInflater with a themed context
+        LayoutInflater inflater = LayoutInflater.from(activity)
+                .cloneInContext(new ContextThemeWrapper(activity, R.style.MagentaThemeOverlay));
+
+        // Now inflate a layout with children
+        final ViewGroup root = (ViewGroup) inflater.inflate(
+                R.layout.layout_children, parent, false);
+
+        // And assert that the layout is themed correctly
+        assertThemedContext(root);
     }
 
     @UiThreadTest
@@ -190,7 +207,7 @@
                 view.getClass());
     }
 
-    private static void assertThemedContext(View view) {
+    private static void assertThemedContext(final View view) {
         final Context viewContext = view.getContext();
         final int expectedColor = view.getResources().getColor(R.color.test_magenta);
 
@@ -199,6 +216,14 @@
                 && colorAccentValue.type <= TypedValue.TYPE_LAST_COLOR_INT);
         assertEquals("View does not have ContextThemeWrapper context",
                 expectedColor, colorAccentValue.data);
+
+        if (view instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) view;
+            for (int i = 0; i < vg.getChildCount(); i++) {
+                final View child = vg.getChildAt(i);
+                assertThemedContext(child);
+            }
+        }
     }
 
     private static TypedValue getColorAccentValue(final Resources.Theme theme) {
diff --git a/v7/cardview/Android.mk b/v7/cardview/Android.mk
index cd3b407..40f6b23 100644
--- a/v7/cardview/Android.mk
+++ b/v7/cardview/Android.mk
@@ -31,6 +31,7 @@
     $(call all-java-files-under,api21) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
 LOCAL_JAR_EXCLUDE_FILES := none
diff --git a/v7/cardview/AndroidManifest-make.xml b/v7/cardview/AndroidManifest-make.xml
new file mode 100644
index 0000000..c35e369
--- /dev/null
+++ b/v7/cardview/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.v7.cardview">
+    <uses-sdk android:minSdkVersion="9"/>
+    <application />
+</manifest>
diff --git a/v7/cardview/AndroidManifest.xml b/v7/cardview/AndroidManifest.xml
index c35e369..e85003c 100644
--- a/v7/cardview/AndroidManifest.xml
+++ b/v7/cardview/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.cardview">
     <uses-sdk android:minSdkVersion="9"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index b88aad7..ce3f28d 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -38,28 +38,11 @@
     }
     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);
 }
 
diff --git a/v7/gridlayout/Android.mk b/v7/gridlayout/Android.mk
index 6eac23b4..c584dbe 100644
--- a/v7/gridlayout/Android.mk
+++ b/v7/gridlayout/Android.mk
@@ -29,6 +29,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-ui \
diff --git a/v7/gridlayout/AndroidManifest-make.xml b/v7/gridlayout/AndroidManifest-make.xml
new file mode 100644
index 0000000..d2cc627
--- /dev/null
+++ b/v7/gridlayout/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.v7.gridlayout">
+    <uses-sdk android:minSdkVersion="9"/>
+    <application />
+</manifest>
diff --git a/v7/gridlayout/AndroidManifest.xml b/v7/gridlayout/AndroidManifest.xml
index d2cc627..dfcc942 100644
--- a/v7/gridlayout/AndroidManifest.xml
+++ b/v7/gridlayout/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.gridlayout">
     <uses-sdk android:minSdkVersion="9"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index 542d5a7..56f320f 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'gridlayout-v7'
 
 dependencies {
@@ -53,28 +52,11 @@
     }
     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);
 }
 
diff --git a/v7/mediarouter/Android.mk b/v7/mediarouter/Android.mk
index 21b4a62..6162f87 100644
--- a/v7/mediarouter/Android.mk
+++ b/v7/mediarouter/Android.mk
@@ -35,6 +35,7 @@
     $(call all-java-files-under,api24) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-appcompat \
     android-support-v7-palette \
diff --git a/v7/mediarouter/AndroidManifest-make.xml b/v7/mediarouter/AndroidManifest-make.xml
new file mode 100644
index 0000000..59d9f99
--- /dev/null
+++ b/v7/mediarouter/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.v7.mediarouter">
+    <uses-sdk android:minSdkVersion="9"/>
+    <application />
+</manifest>
diff --git a/v7/mediarouter/AndroidManifest.xml b/v7/mediarouter/AndroidManifest.xml
index 59d9f99..bbebdfe 100644
--- a/v7/mediarouter/AndroidManifest.xml
+++ b/v7/mediarouter/AndroidManifest.xml
@@ -16,5 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.mediarouter">
     <uses-sdk android:minSdkVersion="9"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index 3e51602..7796565 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -49,28 +49,11 @@
     }
     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);
 }
 
diff --git a/v7/palette/Android.mk b/v7/palette/Android.mk
index c21dad3..a9f9a75 100644
--- a/v7/palette/Android.mk
+++ b/v7/palette/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := src/main/AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-utils \
diff --git a/v7/palette/build.gradle b/v7/palette/build.gradle
index 2494370..686fe71 100644
--- a/v7/palette/build.gradle
+++ b/v7/palette/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'palette-v7'
 
 dependencies {
@@ -34,28 +33,11 @@
     }
     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);
 }
 
diff --git a/v7/palette/src/main/AndroidManifest-make.xml b/v7/palette/src/main/AndroidManifest-make.xml
new file mode 100644
index 0000000..5124bc5
--- /dev/null
+++ b/v7/palette/src/main/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.v7.palette">
+    <uses-sdk android:minSdkVersion="9"/>
+    <application />
+</manifest>
diff --git a/v7/palette/src/main/AndroidManifest.xml b/v7/palette/src/main/AndroidManifest.xml
index c44818a..52e90a2 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/v7/palette/src/main/AndroidManifest.xml
@@ -16,6 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.palette">
     <uses-sdk android:minSdkVersion="9"/>
-    <application>
-    </application>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    <application />
 </manifest>
diff --git a/v7/preference/Android.mk b/v7/preference/Android.mk
index e751e1c..110aed2 100644
--- a/v7/preference/Android.mk
+++ b/v7/preference/Android.mk
@@ -32,6 +32,7 @@
     $(call all-java-files-under,constants) \
     $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v7-appcompat \
     android-support-v7-recyclerview \
diff --git a/v7/preference/AndroidManifest-make.xml b/v7/preference/AndroidManifest-make.xml
new file mode 100644
index 0000000..9231775
--- /dev/null
+++ b/v7/preference/AndroidManifest-make.xml
@@ -0,0 +1,20 @@
+<?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"
+    package="android.support.v7.preference">
+    <uses-sdk android:minSdkVersion="9" />
+    <application />
+</manifest>
diff --git a/v7/preference/AndroidManifest.xml b/v7/preference/AndroidManifest.xml
index da9c80e..19e6215 100644
--- a/v7/preference/AndroidManifest.xml
+++ b/v7/preference/AndroidManifest.xml
@@ -1,8 +1,21 @@
 <?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"
-    package="android.support.v7.preference"
-    android:versionCode="1"
-    android:versionName="1.0">
+    package="android.support.v7.preference">
     <uses-sdk android:minSdkVersion="9" />
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
     <application />
 </manifest>
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index a63cc9e..b5fd656 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -15,7 +15,6 @@
  */
 
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'preference-v7'
 
 dependencies {
@@ -80,28 +79,11 @@
     }
     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);
 }
 
diff --git a/v7/recyclerview/Android.mk b/v7/recyclerview/Android.mk
index e434ab2..819b104 100644
--- a/v7/recyclerview/Android.mk
+++ b/v7/recyclerview/Android.mk
@@ -29,6 +29,7 @@
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := AndroidManifest-make.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-core-ui \
diff --git a/v7/recyclerview/AndroidManifest-make.xml b/v7/recyclerview/AndroidManifest-make.xml
new file mode 100644
index 0000000..d1c1489
--- /dev/null
+++ b/v7/recyclerview/AndroidManifest-make.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.v7.recyclerview">
+    <uses-sdk android:minSdkVersion="9"/>
+</manifest>
diff --git a/v7/recyclerview/AndroidManifest.xml b/v7/recyclerview/AndroidManifest.xml
index d1c1489..f4f010d 100644
--- a/v7/recyclerview/AndroidManifest.xml
+++ b/v7/recyclerview/AndroidManifest.xml
@@ -16,4 +16,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.recyclerview">
     <uses-sdk android:minSdkVersion="9"/>
+    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
 </manifest>
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index 11a098e..e262ec7 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -1,5 +1,4 @@
 apply plugin: 'com.android.library'
-
 archivesBaseName = 'recyclerview-v7'
 
 dependencies {
@@ -47,10 +46,6 @@
         targetCompatibility JavaVersion.VERSION_1_7
     }
 
-    packagingOptions {
-        exclude 'LICENSE.txt'
-    }
-
     testOptions {
         unitTests.returnDefaultValues = true
     }
@@ -68,28 +63,11 @@
     }
     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);
 }
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index 78a31b4..6900437 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -18,12 +18,14 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 import static android.support.v7.widget.RecyclerView.NO_POSITION;
+import static android.support.v7.widget.RecyclerView.VERBOSE_TRACING;
 
 import android.content.Context;
 import android.graphics.PointF;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.support.annotation.RestrictTo;
+import android.support.v4.os.TraceCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityRecordCompat;
@@ -1493,7 +1495,13 @@
         LayoutChunkResult layoutChunkResult = mLayoutChunkResult;
         while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
             layoutChunkResult.resetInternal();
+            if (VERBOSE_TRACING) {
+                TraceCompat.beginSection("LLM LayoutChunk");
+            }
             layoutChunk(recycler, state, layoutState, layoutChunkResult);
+            if (VERBOSE_TRACING) {
+                TraceCompat.endSection();
+            }
             if (layoutChunkResult.mFinished) {
                 break;
             }
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 5fe10bf..24936e0 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -154,6 +154,8 @@
 
     static final boolean DEBUG = false;
 
+    static final boolean VERBOSE_TRACING = false;
+
     private static final int[]  NESTED_SCROLLING_ATTRS
             = {16843830 /* android.R.attr.nestedScrollingEnabled */};
 
@@ -702,7 +704,13 @@
 
             @Override
             public void addView(View child, int index) {
+                if (VERBOSE_TRACING) {
+                    TraceCompat.beginSection("RV addView");
+                }
                 RecyclerView.this.addView(child, index);
+                if (VERBOSE_TRACING) {
+                    TraceCompat.endSection();
+                }
                 dispatchChildAttached(child);
             }
 
@@ -717,7 +725,13 @@
                 if (child != null) {
                     dispatchChildDetached(child);
                 }
+                if (VERBOSE_TRACING) {
+                    TraceCompat.beginSection("RV removeViewAt");
+                }
                 RecyclerView.this.removeViewAt(index);
+                if (VERBOSE_TRACING) {
+                    TraceCompat.endSection();
+                }
             }
 
             @Override
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
index 64111c5..d92b169 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
@@ -279,7 +279,10 @@
                                 item.mText + " (" + item.mId + ")");
                     }
                 });
-        waitFirstLayout();
+        mLayoutManager.expectLayouts(1);
+        setRecyclerView(mRecyclerView);
+        mLayoutManager.waitForLayout(10);
+        getInstrumentation().waitForIdleSync();
         ViewGroup lastChild = (ViewGroup) mRecyclerView.getChildAt(
                 mRecyclerView.getChildCount() - 1);
         RecyclerView.ViewHolder lastViewHolder = mRecyclerView.getChildViewHolder(lastChild);