Merge "Include licenses in maven pom"
diff --git a/api/current.txt b/api/current.txt
index db8f801..8757fb5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1678,13 +1678,13 @@
 
 package android.support.percent {
 
-  public class PercentFrameLayout extends android.widget.FrameLayout {
+  public deprecated class PercentFrameLayout extends android.widget.FrameLayout {
     ctor public PercentFrameLayout(android.content.Context);
     ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet);
     ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet, int);
   }
 
-  public static class PercentFrameLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+  public static deprecated class PercentFrameLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
     ctor public PercentFrameLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
     ctor public PercentFrameLayout.LayoutParams(int, int);
     ctor public PercentFrameLayout.LayoutParams(int, int, int);
@@ -1695,7 +1695,7 @@
     method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
   }
 
-  public class PercentLayoutHelper {
+  public deprecated class PercentLayoutHelper {
     ctor public PercentLayoutHelper(android.view.ViewGroup);
     method public void adjustChildren(int, int);
     method public static void fetchWidthAndHeight(android.view.ViewGroup.LayoutParams, android.content.res.TypedArray, int, int);
@@ -1704,7 +1704,7 @@
     method public void restoreOriginalParams();
   }
 
-  public static class PercentLayoutHelper.PercentLayoutInfo {
+  public static deprecated class PercentLayoutHelper.PercentLayoutInfo {
     ctor public PercentLayoutHelper.PercentLayoutInfo();
     method public void fillLayoutParams(android.view.ViewGroup.LayoutParams, int, int);
     method public deprecated void fillMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams, int, int);
@@ -1722,17 +1722,17 @@
     field public float widthPercent;
   }
 
-  public static abstract interface PercentLayoutHelper.PercentLayoutParams {
+  public static abstract deprecated interface PercentLayoutHelper.PercentLayoutParams {
     method public abstract android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
   }
 
-  public class PercentRelativeLayout extends android.widget.RelativeLayout {
+  public deprecated class PercentRelativeLayout extends android.widget.RelativeLayout {
     ctor public PercentRelativeLayout(android.content.Context);
     ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet);
     ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet, int);
   }
 
-  public static class PercentRelativeLayout.LayoutParams extends android.widget.RelativeLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+  public static deprecated class PercentRelativeLayout.LayoutParams extends android.widget.RelativeLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
     ctor public PercentRelativeLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
     ctor public PercentRelativeLayout.LayoutParams(int, int);
     ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
@@ -2865,6 +2865,9 @@
     method protected abstract int getPageCount();
     method protected abstract java.lang.CharSequence getPageDescription(int);
     method protected abstract java.lang.CharSequence getPageTitle(int);
+    method protected final boolean isLogoAnimationFinished();
+    method protected void moveToNextPage();
+    method protected void moveToPreviousPage();
     method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected android.animation.Animator onCreateDescriptionAnimator();
@@ -2873,6 +2876,7 @@
     method protected android.animation.Animator onCreateLogoAnimation();
     method protected android.animation.Animator onCreateTitleAnimator();
     method protected void onFinishFragment();
+    method protected void onLogoAnimationFinished();
     method protected void onPageChanged(int, int);
     method public int onProvideTheme();
     method public final void setIconResouceId(int);
@@ -2887,6 +2891,9 @@
     method protected abstract int getPageCount();
     method protected abstract java.lang.CharSequence getPageDescription(int);
     method protected abstract java.lang.CharSequence getPageTitle(int);
+    method protected final boolean isLogoAnimationFinished();
+    method protected void moveToNextPage();
+    method protected void moveToPreviousPage();
     method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
     method protected android.animation.Animator onCreateDescriptionAnimator();
@@ -2895,6 +2902,7 @@
     method protected android.animation.Animator onCreateLogoAnimation();
     method protected android.animation.Animator onCreateTitleAnimator();
     method protected void onFinishFragment();
+    method protected void onLogoAnimationFinished();
     method protected void onPageChanged(int, int);
     method public int onProvideTheme();
     method public final void setIconResouceId(int);
diff --git a/buildSrc/diff_and_docs.gradle b/buildSrc/diff_and_docs.gradle
index c7da87c..2034c15 100644
--- a/buildSrc/diff_and_docs.gradle
+++ b/buildSrc/diff_and_docs.gradle
@@ -25,20 +25,43 @@
 
 import groovy.io.FileType
 
-// Generates API files for the current SDK. This is necessary for federation.
-task generateSdkApi(type: DoclavaTask, dependsOn: [configurations.doclava]) {
-    docletpath = configurations.doclava.resolve()
-    destinationDir = project.docsDir
+// Set up platform API files for federation.
+if (project.androidApiTxt != null) {
+    task generateSdkApi(type: Copy) {
+        description = 'Copies the API files for the current SDK.'
 
-    classpath = project.androidJar
-    source zipTree(project.androidSrcJar)
+        // Export the API files so this looks like a DoclavaTask.
+        ext.apiFile = new File(project.docsDir, 'release/sdk_current.txt')
+        ext.removedApiFile = new File(project.docsDir, 'release/sdk_removed.txt')
 
-    apiFile = new File(project.docsDir, 'release/sdk_current.txt')
-    removedApiFile = new File(project.docsDir, 'release/sdk_removed.txt')
-    generateDocs = false
+        from project.androidApiTxt.absolutePath
+        into apiFile.parent
+        rename { apiFile.name }
 
-    options {
-        addStringOption "stubpackages", "android.*"
+        // Register the fake removed file as an output.
+        outputs.file removedApiFile
+
+        doLast {
+            removedApiFile.createNewFile()
+        }
+    }
+} else {
+    task generateSdkApi(type: DoclavaTask, dependsOn: [configurations.doclava]) {
+        description = 'Generates API files for the current SDK.'
+
+        docletpath = configurations.doclava.resolve()
+        destinationDir = project.docsDir
+
+        classpath = project.androidJar
+        source zipTree(project.androidSrcJar)
+
+        apiFile = new File(project.docsDir, 'release/sdk_current.txt')
+        removedApiFile = new File(project.docsDir, 'release/sdk_removed.txt')
+        generateDocs = false
+
+        options {
+            addStringOption "stubpackages", "android.*"
+        }
     }
 }
 
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index 5005c10..7337c53 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -84,6 +84,7 @@
                 files("${fullSdkPath}/platforms/android-${gradle.currentSdk}/android.jar")
         project.ext.androidSrcJar =
                 file("${fullSdkPath}/platforms/android-${gradle.currentSdk}/android-stubs-src.jar")
+        project.ext.androidApiTxt = null
         System.setProperty('android.home', "${init.prebuiltsRoot}/fullsdk-${platform}")
         File props = file("local.properties")
         props.write "sdk.dir=${fullSdkPath}"
@@ -91,7 +92,8 @@
     } else {
         gradle.ext.currentSdk = 'current'
         project.ext.androidJar = files("${init.prebuiltsRoot}/sdk/current/android.jar")
-        project.ext.androidSrcJar = files("${init.prebuiltsRoot}/sdk/current/android-stubs-src.jar")
+        project.ext.androidSrcJar = null
+        project.ext.androidApiTxt = file("${init.prebuiltsRoot}/sdk/api/26.txt")
         File props = file("local.properties")
         props.write "android.dir=../../"
         ext.usingFullSdk = false
diff --git a/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java b/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
index 4bd67a3..db3f318 100644
--- a/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
+++ b/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
@@ -61,9 +61,14 @@
      */
     public DoclavaJavadocOptionFileOption duplicate() {
         final Iterable<String> value = getValue();
-        final ArrayList<String> valueCopy = new ArrayList<>();
-        for (String item : value) {
-            valueCopy.add(item);
+        final ArrayList<String> valueCopy;
+        if (value != null) {
+            valueCopy = new ArrayList<>();
+            for (String item : value) {
+                valueCopy.add(item);
+            }
+        } else {
+            valueCopy = null;
         }
         return new DoclavaJavadocOptionFileOption(getOption(), valueCopy);
     }
diff --git a/compat/AndroidManifest.xml b/compat/AndroidManifest.xml
index 6a9f6a6..09383ee 100644
--- a/compat/AndroidManifest.xml
+++ b/compat/AndroidManifest.xml
@@ -17,6 +17,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.compat">
     <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.compat"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index 54c2730..60f8ba7 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -19,7 +19,6 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.animation.ValueAnimator;
-import android.support.annotation.RequiresApi;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -35,6 +34,7 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
 import android.support.v4.os.BuildCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -468,11 +468,11 @@
         }
 
         public void postInvalidateOnAnimation(View view) {
-            view.invalidate();
+            view.postInvalidate();
         }
 
         public void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom) {
-            view.invalidate(left, top, right, bottom);
+            view.postInvalidate(left, top, right, bottom);
         }
 
         public void postOnAnimation(View view, Runnable action) {
diff --git a/core-ui/AndroidManifest.xml b/core-ui/AndroidManifest.xml
index 61eba66..b952b5e 100644
--- a/core-ui/AndroidManifest.xml
+++ b/core-ui/AndroidManifest.xml
@@ -17,6 +17,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreui">
     <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.coreui"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/core-utils/AndroidManifest.xml b/core-utils/AndroidManifest.xml
index b3b404b..5c10a5b 100644
--- a/core-utils/AndroidManifest.xml
+++ b/core-utils/AndroidManifest.xml
@@ -17,6 +17,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.coreutils">
     <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.coreutils"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/customtabs/AndroidManifest.xml b/customtabs/AndroidManifest.xml
index 19a1d54..4069dae 100644
--- a/customtabs/AndroidManifest.xml
+++ b/customtabs/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <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 />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/design/AndroidManifest.xml b/design/AndroidManifest.xml
index e4449de..afae16e 100644
--- a/design/AndroidManifest.xml
+++ b/design/AndroidManifest.xml
@@ -18,6 +18,7 @@
           package="android.support.design">
     <uses-sdk android:minSdkVersion="14"
               tools:overrideLibrary="android.support.transition"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/dynamic-animation/AndroidManifest.xml b/dynamic-animation/AndroidManifest.xml
index 9e83183..f818402 100644
--- a/dynamic-animation/AndroidManifest.xml
+++ b/dynamic-animation/AndroidManifest.xml
@@ -16,5 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.dynamicanimation">
     <uses-sdk android:minSdkVersion="16"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/emoji/appcompat/AndroidManifest.xml b/emoji/appcompat/AndroidManifest.xml
index 81bc0f8..56d8ab5 100644
--- a/emoji/appcompat/AndroidManifest.xml
+++ b/emoji/appcompat/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.text.emoji.appcompat">
     <uses-sdk android:minSdkVersion="19"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/emoji/bundled-typeface/AndroidManifest.xml b/emoji/bundled-typeface/AndroidManifest.xml
index 2c5bc46..5bb7578 100644
--- a/emoji/bundled-typeface/AndroidManifest.xml
+++ b/emoji/bundled-typeface/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.text.emoji.typeface">
     <uses-sdk android:minSdkVersion="19"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}"/>
-    <application/>
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
\ No newline at end of file
diff --git a/emoji/core/AndroidManifest.xml b/emoji/core/AndroidManifest.xml
index b288921..815858d 100644
--- a/emoji/core/AndroidManifest.xml
+++ b/emoji/core/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.text.emoji">
     <uses-sdk android:minSdkVersion="19"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index 2592cb1..0e94d4e 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -20,6 +20,7 @@
     androidTestCompile libs.mockito_core
     androidTestCompile libs.dexmaker
     androidTestCompile libs.dexmaker_mockito
+    androidTestCompile project(path: ':support-testutils')
 }
 
 android {
diff --git a/emoji/core/src/android/support/text/emoji/EmojiProcessor.java b/emoji/core/src/android/support/text/emoji/EmojiProcessor.java
index 9712b80..9275a6e 100644
--- a/emoji/core/src/android/support/text/emoji/EmojiProcessor.java
+++ b/emoji/core/src/android/support/text/emoji/EmojiProcessor.java
@@ -457,9 +457,10 @@
      */
     private boolean hasGlyph(final CharSequence charSequence, int start, final int end,
             final EmojiMetadata metadata) {
-        // if the emoji was added to OS at a later version we know that the system cannot render it.
-        // without this check pre M devices result in more false positives.
-        if (metadata.getSdkAdded() > Build.VERSION.SDK_INT) {
+        // For pre M devices, heuristic in PaintCompat can result in false positives. we are
+        // adding another heuristic using the sdkAdded field. if the emoji was added to OS
+        // at a later version we assume that the system probably cannot render it.
+        if (Build.VERSION.SDK_INT < 23 && metadata.getSdkAdded() > Build.VERSION.SDK_INT) {
             return false;
         }
 
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java
index eb0ba3a..22ee475 100644
--- a/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java
+++ b/emoji/core/tests/java/android/support/text/emoji/EmojiInstrumentationTest.java
@@ -34,16 +34,15 @@
 import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.testutils.PollingCheck;
 import android.support.text.emoji.test.R;
 import android.support.text.emoji.util.KeyboardUtil;
 import android.support.text.emoji.util.TestString;
 import android.text.Editable;
-import android.text.Selection;
 import android.text.Spannable;
 import android.text.Spanned;
 import android.text.style.RelativeSizeSpan;
 import android.util.TypedValue;
-import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.widget.EditText;
 import android.widget.TextView;
@@ -102,7 +101,8 @@
 
         // cover the charsequence with RelativeSizeSpan which will triple the size of the
         // characters.
-        final RelativeSizeSpan sizeSpan = new RelativeSizeSpan(3.0f);
+        final float multiplier = 3.0f;
+        final RelativeSizeSpan sizeSpan = new RelativeSizeSpan(multiplier);
         spanned.setSpan(sizeSpan, 0, charSequence.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
         // set the new text
         mInstrumentation.runOnMainSync(new Runnable() {
@@ -128,18 +128,13 @@
         final EditText editText = (EditText) activity.findViewById(R.id.editText);
         final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
                 .withSuffix();
-        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
 
+        final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme(
+                mInstrumentation, editText);
+        KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection,
+                string.toString());
         Editable editable = editText.getEditableText();
 
-        // 0xf0950 is the remapped codepoint for WOMEN_WITH_BALL
         assertThat(editable, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(),
                 string.emojiEndIndex()));
     }
@@ -150,25 +145,19 @@
         final EditText editText = (EditText) activity.findViewById(R.id.editText);
         final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
                 .withSuffix();
-        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
-                Selection.setSelection(editText.getEditableText(), string.emojiEndIndex());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme(
+                mInstrumentation, editText);
+        KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString());
+
+        // assert that emoji is there
         final Editable editable = editText.getEditableText();
         assertThat(editable, hasEmoji());
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                KeyboardUtil.deleteSurrondingText(inputConnection, 1, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        // put selection at the end of emoji and back delete
+        KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(),
+                string.emojiEndIndex());
+        KeyboardUtil.deleteSurroundingText(mInstrumentation, inputConnection, 1, 0);
+
         assertThat(editable, not(hasEmoji()));
     }
 
@@ -178,25 +167,20 @@
         final EditText editText = (EditText) activity.findViewById(R.id.editText);
         final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
                 .withSuffix();
-        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
-                Selection.setSelection(editText.getEditableText(), string.emojiStartIndex());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme(
+                mInstrumentation, editText);
+        KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString());
+
+        // assert that emoji is there
         final Editable editable = editText.getEditableText();
         assertThat(editable, hasEmoji());
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                KeyboardUtil.deleteSurrondingText(inputConnection, 0, 1);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        // put selection at the begining of emoji and forward delete
+        KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(),
+                string.emojiStartIndex());
+        KeyboardUtil.deleteSurroundingText(mInstrumentation, inputConnection, 0, 1);
+
+
         assertThat(editable, not(hasEmoji()));
     }
 
@@ -206,21 +190,26 @@
         final EditText editText = (EditText) activity.findViewById(R.id.editText);
         final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
                 .withSuffix();
-        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
-                Selection.setSelection(editText.getEditableText(), string.emojiEndIndex());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme(
+                mInstrumentation, editText);
+        KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString());
+
+        // assert that emoji is there
         final Editable editable = editText.getEditableText();
         assertThat(editable, hasEmoji());
 
-
+        // put selection at the end of emoji and back delete
+        KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(),
+                string.emojiEndIndex());
         mInstrumentation.sendKeySync(del());
         mInstrumentation.waitForIdleSync();
+
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return not(hasEmoji()).matches(true);
+            }
+        });
         assertThat(editable, not(hasEmoji()));
     }
 
@@ -230,20 +219,26 @@
         final EditText editText = (EditText) activity.findViewById(R.id.editText);
         final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix()
                 .withSuffix();
-        final InputConnection inputConnection = editText.onCreateInputConnection(new EditorInfo());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                KeyboardUtil.setComposingTextInBatch(inputConnection, string.toString());
-                Selection.setSelection(editText.getEditableText(), string.emojiStartIndex());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme(
+                mInstrumentation, editText);
+        KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString());
+
+        // assert that emoji is there
         final Editable editable = editText.getEditableText();
         assertThat(editable, hasEmoji());
 
+        // put selection at the begining of emoji and forward delete
+        KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(),
+                string.emojiStartIndex());
         mInstrumentation.sendKeySync(forwardDel());
         mInstrumentation.waitForIdleSync();
+
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return not(hasEmoji()).matches(true);
+            }
+        });
         assertThat(editable, not(hasEmoji()));
     }
 }
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java b/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
index 4764455..0c89b2d 100644
--- a/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
+++ b/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
@@ -15,8 +15,17 @@
  */
 package android.support.text.emoji.util;
 
+import android.app.Instrumentation;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.method.QwertyKeyListener;
+import android.text.method.TextKeyListener;
 import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.widget.TextView;
+
+import java.util.concurrent.CountDownLatch;
 
 /**
  * Utility class for KeyEvents
@@ -65,15 +74,74 @@
         return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0);
     }
 
-    public static void setComposingTextInBatch(InputConnection input, CharSequence text) {
-        input.beginBatchEdit();
-        input.setComposingText(text, 1);
-        input.endBatchEdit();
+    public static void setComposingTextInBatch(final Instrumentation instrumentation,
+            final InputConnection inputConnection, final CharSequence text)
+            throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                inputConnection.beginBatchEdit();
+                inputConnection.setComposingText(text, 1);
+                inputConnection.endBatchEdit();
+                latch.countDown();
+            }
+        });
+
+        latch.await();
+        instrumentation.waitForIdleSync();
     }
 
-    public static void deleteSurrondingText(InputConnection input, int before, int after) {
-        input.beginBatchEdit();
-        input.deleteSurroundingText(before, after);
-        input.endBatchEdit();
+    public static void deleteSurroundingText(final Instrumentation instrumentation,
+            final InputConnection inputConnection, final int before, final int after)
+            throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                inputConnection.beginBatchEdit();
+                inputConnection.deleteSurroundingText(before, after);
+                inputConnection.endBatchEdit();
+                latch.countDown();
+            }
+        });
+        latch.await();
+        instrumentation.waitForIdleSync();
+    }
+
+    public static void setSelection(Instrumentation instrumentation, final Spannable spannable,
+            final int start) throws InterruptedException {
+        setSelection(instrumentation, spannable, start, start);
+    }
+
+    public static void setSelection(Instrumentation instrumentation, final Spannable spannable,
+            final int start, final int end) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                Selection.setSelection(spannable, start, end);
+                latch.countDown();
+            }
+        });
+        latch.await();
+        instrumentation.waitForIdleSync();
+    }
+
+    public static InputConnection initTextViewForSimulatedIme(Instrumentation instrumentation,
+            final TextView textView) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setKeyListener(
+                        QwertyKeyListener.getInstance(false, TextKeyListener.Capitalize.NONE));
+                textView.setText("", TextView.BufferType.EDITABLE);
+                latch.countDown();
+            }
+        });
+        latch.await();
+        instrumentation.waitForIdleSync();
+        return textView.onCreateInputConnection(new EditorInfo());
     }
 }
diff --git a/emoji/core/tests/res/layout/activity_default.xml b/emoji/core/tests/res/layout/activity_default.xml
index b9a09ca..c8341b8 100644
--- a/emoji/core/tests/res/layout/activity_default.xml
+++ b/emoji/core/tests/res/layout/activity_default.xml
@@ -9,7 +9,8 @@
     <TextView
         android:id="@+id/text"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
+        android:layout_height="wrap_content"
+        android:textSize="8sp"/>
 
     <android.support.text.emoji.widget.EmojiEditText
         android:id="@+id/editText"
diff --git a/exifinterface/AndroidManifest.xml b/exifinterface/AndroidManifest.xml
index 94b3300..344b99b 100644
--- a/exifinterface/AndroidManifest.xml
+++ b/exifinterface/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.exifinterface">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/fragment/AndroidManifest.xml b/fragment/AndroidManifest.xml
index c6fdcc4..725fe43 100644
--- a/fragment/AndroidManifest.xml
+++ b/fragment/AndroidManifest.xml
@@ -17,6 +17,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.fragment">
     <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.fragment"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 84939b4..5bc6b35 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.3-bin.zip
+distributionUrl=../../../../tools/external/gradle/gradle-3.4-bin.zip
diff --git a/graphics/drawable/animated/AndroidManifest.xml b/graphics/drawable/animated/AndroidManifest.xml
index 58017dc..b59fa47 100644
--- a/graphics/drawable/animated/AndroidManifest.xml
+++ b/graphics/drawable/animated/AndroidManifest.xml
@@ -16,6 +16,7 @@
   -->
 <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/>
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/graphics/drawable/static/AndroidManifest.xml b/graphics/drawable/static/AndroidManifest.xml
index 0383e4c..14821a8 100644
--- a/graphics/drawable/static/AndroidManifest.xml
+++ b/graphics/drawable/static/AndroidManifest.xml
@@ -16,6 +16,7 @@
   -->
 <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}" />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/instantvideo/AndroidManifest.xml b/instantvideo/AndroidManifest.xml
index 08ebcbe..26b46c0 100644
--- a/instantvideo/AndroidManifest.xml
+++ b/instantvideo/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.media.instantvideo">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/media-compat/AndroidManifest.xml b/media-compat/AndroidManifest.xml
index 4e73a70..f5e74a2 100644
--- a/media-compat/AndroidManifest.xml
+++ b/media-compat/AndroidManifest.xml
@@ -17,6 +17,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.mediacompat">
     <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.mediacompat"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/percent/AndroidManifest.xml b/percent/AndroidManifest.xml
index fd770ab..58eebfe 100644
--- a/percent/AndroidManifest.xml
+++ b/percent/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.percent">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/percent/build.gradle b/percent/build.gradle
index 1dc9490..90c2962 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -3,7 +3,6 @@
 
 dependencies {
     compile project(':support-compat')
-
     androidTestCompile (libs.test_runner) {
         exclude module: 'support-annotations'
     }
diff --git a/percent/src/android/support/percent/PercentFrameLayout.java b/percent/src/android/support/percent/PercentFrameLayout.java
index 9dce2bb..b9abd39 100644
--- a/percent/src/android/support/percent/PercentFrameLayout.java
+++ b/percent/src/android/support/percent/PercentFrameLayout.java
@@ -74,7 +74,60 @@
  * </pre>
  * This will make the aspect ratio 16:9 (1.78:1) with the width fixed at 300dp and height adjusted
  * accordingly.
+ *
+ * @deprecated consider using ConstraintLayout and associated layouts instead. The following shows
+ * how to replicate the functionality of percentage layouts with a ConstraintLayout. The Guidelines
+ * are used to define each percentage break point, and then a Button view is stretched to fill
+ * the gap:
+ *
+ * <pre class="prettyprint">
+ * &lt;android.support.constraint.ConstraintLayout
+ *         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"&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/left_guideline"
+ *         app:layout_constraintGuide_percent=".15"
+ *         android:orientation="vertical"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/right_guideline"
+ *         app:layout_constraintGuide_percent=".85"
+ *         android:orientation="vertical"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/top_guideline"
+ *         app:layout_constraintGuide_percent=".15"
+ *         android:orientation="horizontal"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/bottom_guideline"
+ *         app:layout_constraintGuide_percent=".85"
+ *         android:orientation="horizontal"/&gt
+ *
+ *     &lt;Button
+ *         android:text="Button"
+ *         android:layout_width="0dp"
+ *         android:layout_height="0dp"
+ *         android:id="@+id/button"
+ *         app:layout_constraintLeft_toLeftOf="@+id/left_guideline"
+ *         app:layout_constraintRight_toRightOf="@+id/right_guideline"
+ *         app:layout_constraintTop_toTopOf="@+id/top_guideline"
+ *         app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline" /&gt
+ *
+ * &lt;/android.support.constraint.ConstraintLayout&gt
  */
+@Deprecated
 public class PercentFrameLayout extends FrameLayout {
     private final PercentLayoutHelper mHelper = new PercentLayoutHelper(this);
 
@@ -115,6 +168,10 @@
         mHelper.restoreOriginalParams();
     }
 
+    /**
+     * @deprecated this class is deprecated along with its parent class.
+     */
+    @Deprecated
     public static class LayoutParams extends FrameLayout.LayoutParams
             implements PercentLayoutHelper.PercentLayoutParams {
         private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
diff --git a/percent/src/android/support/percent/PercentLayoutHelper.java b/percent/src/android/support/percent/PercentLayoutHelper.java
index d681244..44a76c7 100644
--- a/percent/src/android/support/percent/PercentLayoutHelper.java
+++ b/percent/src/android/support/percent/PercentLayoutHelper.java
@@ -67,7 +67,59 @@
  * }
  * </pre>
  * </ol>
+ * @deprecated consider using ConstraintLayout and associated layouts instead. The following shows
+ * how to replicate the functionality of percentage layouts with a ConstraintLayout. The Guidelines
+ * are used to define each percentage break point, and then a Button view is stretched to fill
+ * the gap:
+ *
+ * <pre class="prettyprint">
+ * &lt;android.support.constraint.ConstraintLayout
+ *         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"&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/left_guideline"
+ *         app:layout_constraintGuide_percent=".15"
+ *         android:orientation="vertical"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/right_guideline"
+ *         app:layout_constraintGuide_percent=".85"
+ *         android:orientation="vertical"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/top_guideline"
+ *         app:layout_constraintGuide_percent=".15"
+ *         android:orientation="horizontal"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/bottom_guideline"
+ *         app:layout_constraintGuide_percent=".85"
+ *         android:orientation="horizontal"/&gt
+ *
+ *     &lt;Button
+ *         android:text="Button"
+ *         android:layout_width="0dp"
+ *         android:layout_height="0dp"
+ *         android:id="@+id/button"
+ *         app:layout_constraintLeft_toLeftOf="@+id/left_guideline"
+ *         app:layout_constraintRight_toRightOf="@+id/right_guideline"
+ *         app:layout_constraintTop_toTopOf="@+id/top_guideline"
+ *         app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline" /&gt
+ *
+ * &lt;/android.support.constraint.ConstraintLayout&gt
  */
+@Deprecated
 public class PercentLayoutHelper {
     private static final String TAG = "PercentLayout";
 
@@ -344,7 +396,10 @@
     /**
      * Container for information about percentage dimensions and margins. It acts as an extension
      * for {@code LayoutParams}.
+     *
+     * @deprecated use ConstraintLayout and Guidelines for layout support.
      */
+    @Deprecated
     public static class PercentLayoutInfo {
         /** The decimal value of the percentage-based width. */
         public float widthPercent;
@@ -555,7 +610,10 @@
      *
      * Your {@code LayoutParams} subclass should contain an instance of {@code PercentLayoutInfo}
      * and the implementation of this interface should be a simple accessor.
+     *
+     * @deprecated this class is deprecated along with its parent class.
      */
+    @Deprecated
     public interface PercentLayoutParams {
         PercentLayoutInfo getPercentLayoutInfo();
     }
diff --git a/percent/src/android/support/percent/PercentRelativeLayout.java b/percent/src/android/support/percent/PercentRelativeLayout.java
index f068d6b..5b10349 100644
--- a/percent/src/android/support/percent/PercentRelativeLayout.java
+++ b/percent/src/android/support/percent/PercentRelativeLayout.java
@@ -73,7 +73,60 @@
  * </pre>
  * This will make the aspect ratio 16:9 (1.78:1) with the width fixed at 300dp and height adjusted
  * accordingly.
+ *
+ * @deprecated consider using ConstraintLayout and associated layouts instead. The following shows
+ * how to replicate the functionality of percentage layouts with a ConstraintLayout. The Guidelines
+ * are used to define each percentage break point, and then a Button view is stretched to fill
+ * the gap:
+ *
+ * <pre class="prettyprint">
+ * &lt;android.support.constraint.ConstraintLayout
+ *         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"&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/left_guideline"
+ *         app:layout_constraintGuide_percent=".15"
+ *         android:orientation="vertical"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/right_guideline"
+ *         app:layout_constraintGuide_percent=".85"
+ *         android:orientation="vertical"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/top_guideline"
+ *         app:layout_constraintGuide_percent=".15"
+ *         android:orientation="horizontal"/&gt
+ *
+ *     &lt;android.support.constraint.Guideline
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:id="@+id/bottom_guideline"
+ *         app:layout_constraintGuide_percent=".85"
+ *         android:orientation="horizontal"/&gt
+ *
+ *     &lt;Button
+ *         android:text="Button"
+ *         android:layout_width="0dp"
+ *         android:layout_height="0dp"
+ *         android:id="@+id/button"
+ *         app:layout_constraintLeft_toLeftOf="@+id/left_guideline"
+ *         app:layout_constraintRight_toRightOf="@+id/right_guideline"
+ *         app:layout_constraintTop_toTopOf="@+id/top_guideline"
+ *         app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline" /&gt
+ *
+ * &lt;/android.support.constraint.ConstraintLayout&gt
  */
+@Deprecated
 public class PercentRelativeLayout extends RelativeLayout {
     private final PercentLayoutHelper mHelper = new PercentLayoutHelper(this);
 
@@ -114,6 +167,10 @@
         mHelper.restoreOriginalParams();
     }
 
+    /**
+     * @deprecated this class is deprecated along with its parent class.
+     */
+    @Deprecated
     public static class LayoutParams extends RelativeLayout.LayoutParams
             implements PercentLayoutHelper.PercentLayoutParams {
         private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
diff --git a/recommendation/AndroidManifest.xml b/recommendation/AndroidManifest.xml
index e36c822..09017e0 100644
--- a/recommendation/AndroidManifest.xml
+++ b/recommendation/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <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 />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/samples/Support7Demos/res/layout/popup_menu_activity.xml b/samples/Support7Demos/res/layout/popup_menu_activity.xml
index c3ed4f5..552a996 100644
--- a/samples/Support7Demos/res/layout/popup_menu_activity.xml
+++ b/samples/Support7Demos/res/layout/popup_menu_activity.xml
@@ -27,6 +27,16 @@
         android:layout_centerHorizontal="true"
         android:text="@string/popup_menu_button" />
 
+    <android.support.v7.widget.SwitchCompat
+        android:id="@+id/elevation_toggle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/test_button"
+        android:layout_marginLeft="8dp"
+        android:layout_marginRight="8dp"
+        android:checked="true"
+        android:text="@string/popup_default_elevation" />
+
     <TextView
         android:id="@+id/log"
         android:layout_width="match_parent"
diff --git a/samples/Support7Demos/res/values-v21/styles.xml b/samples/Support7Demos/res/values-v21/styles.xml
index d5b1764..f75030d 100644
--- a/samples/Support7Demos/res/values-v21/styles.xml
+++ b/samples/Support7Demos/res/values-v21/styles.xml
@@ -24,4 +24,8 @@
         <item name="windowActionModeOverlay">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
-</resources>
\ No newline at end of file
+
+    <style name="CustomPopupNoElevation" parent="@style/Widget.AppCompat.Light.PopupMenu">
+        <item name="android:popupElevation">2dp</item>
+    </style>
+</resources>
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 33adf07c..c5ffe46 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -218,6 +218,7 @@
     <string name="popup_menu_activity">AppCompat/Popup menu</string>
     <string name="popup_menu_summary">This activity illustrates the use of popup menus. The popup menu is shown by clicking the button above. The text area below logs various events.</string>
     <string name="popup_menu_button">Show popup!</string>
+    <string name="popup_default_elevation">Use default elevation on popup</string>
     <string name="popup_menu_highlight">Highlight</string>
     <string name="popup_menu_highlight_description">Highlight description</string>
     <string name="popup_menu_highlight_tooltip">Highlight tooltip</string>
diff --git a/samples/Support7Demos/res/values/styles.xml b/samples/Support7Demos/res/values/styles.xml
index 98f8d07..9c022d3 100644
--- a/samples/Support7Demos/res/values/styles.xml
+++ b/samples/Support7Demos/res/values/styles.xml
@@ -56,4 +56,6 @@
         <item name="windowActionModeOverlay">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
+
+    <style name="CustomPopupNoElevation" parent="@style/Widget.AppCompat.Light.PopupMenu" />
 </resources>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java
index bb7cd86..3adf840 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/PopupMenuActivity.java
@@ -20,26 +20,23 @@
 import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.PopupMenu;
+import android.support.v7.widget.SwitchCompat;
+import android.view.Gravity;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.TextView;
+
 import com.example.android.supportv7.R;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
 public class PopupMenuActivity extends AppCompatActivity {
-    private ViewGroup mContainer;
-
     private TextView mLog;
 
-    private Button mButton;
-
-    private PopupMenu mPopupMenu;
-
     private SimpleDateFormat mDateFormat;
 
     @Override
@@ -50,17 +47,29 @@
 
         mDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
 
-        mContainer = (ViewGroup) findViewById(R.id.container);
-        mLog = (TextView) mContainer.findViewById(R.id.log);
-        mButton = (Button) mContainer.findViewById(R.id.test_button);
+        final ViewGroup container = (ViewGroup) findViewById(R.id.container);
+        mLog = (TextView) container.findViewById(R.id.log);
 
-        mButton.setOnClickListener(new View.OnClickListener() {
+        final SwitchCompat elevationToggle = (SwitchCompat) container.findViewById(
+                R.id.elevation_toggle);
+        final Button button = (Button) container.findViewById(R.id.test_button);
+        button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mPopupMenu = new PopupMenu(mContainer.getContext(), mButton);
-                final MenuInflater menuInflater = mPopupMenu.getMenuInflater();
-                menuInflater.inflate(R.menu.popup_menu, mPopupMenu.getMenu());
-                final MenuItem editItem = mPopupMenu.getMenu().findItem(R.id.action_edit);
+                // Do we need to use a custom style that removes elevation?
+                boolean useDefaultElevation = elevationToggle.isChecked();
+
+                PopupMenu popupMenu = null;
+                if (useDefaultElevation) {
+                    popupMenu = new PopupMenu(container.getContext(), button);
+                } else {
+                    popupMenu = new PopupMenu(container.getContext(), button, Gravity.NO_GRAVITY,
+                            0, R.style.CustomPopupNoElevation);
+                }
+
+                final MenuInflater menuInflater = popupMenu.getMenuInflater();
+                menuInflater.inflate(R.menu.popup_menu, popupMenu.getMenu());
+                final MenuItem editItem = popupMenu.getMenu().findItem(R.id.action_edit);
                 MenuItemCompat.setContentDescription(editItem,
                         getString(R.string.popup_menu_edit_description));
                 MenuItemCompat.setTooltipText(editItem,
@@ -68,7 +77,7 @@
 
                 // Register a listener to be notified when a menu item in our popup menu has
                 // been clicked.
-                mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                     @Override
                     public boolean onMenuItemClick(MenuItem item) {
                         addToLog("Item '"+ item.getTitle() + "' clicked");
@@ -77,7 +86,7 @@
                 });
 
                 // Register a listener to be notified when our popup menu is dismissed.
-                mPopupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
+                popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
                     @Override
                     public void onDismiss(PopupMenu menu) {
                         addToLog("Popup menu dismissed");
@@ -85,7 +94,7 @@
                 });
 
                 // Show the popup menu
-                mPopupMenu.show();
+                popupMenu.show();
             }
         });
     }
diff --git a/transition/AndroidManifest.xml b/transition/AndroidManifest.xml
index 1059f63..309b695 100644
--- a/transition/AndroidManifest.xml
+++ b/transition/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <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 />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/tv-provider/AndroidManifest.xml b/tv-provider/AndroidManifest.xml
index 39c540a..f07d090 100644
--- a/tv-provider/AndroidManifest.xml
+++ b/tv-provider/AndroidManifest.xml
@@ -18,6 +18,7 @@
     <uses-sdk android:minSdkVersion="21"/>
     <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
     <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v13/AndroidManifest.xml b/v13/AndroidManifest.xml
index 65ef182..6eea520 100644
--- a/v13/AndroidManifest.xml
+++ b/v13/AndroidManifest.xml
@@ -17,6 +17,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v13">
     <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.v13"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}"/>
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v14/preference/AndroidManifest.xml b/v14/preference/AndroidManifest.xml
index 74cff2e..95bab75 100644
--- a/v14/preference/AndroidManifest.xml
+++ b/v14/preference/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.support.v14.preference">
     <uses-sdk android:minSdkVersion="14" />
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v17/leanback/AndroidManifest.xml b/v17/leanback/AndroidManifest.xml
index ded4ce8..9176231 100644
--- a/v17/leanback/AndroidManifest.xml
+++ b/v17/leanback/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <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 />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v17/leanback/res/values-da/strings.xml b/v17/leanback/res/values-da/strings.xml
index cf0e26e..3881fd6 100644
--- a/v17/leanback/res/values-da/strings.xml
+++ b/v17/leanback/res/values-da/strings.xml
@@ -49,7 +49,7 @@
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver undertekster"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Tilføj billedet i billedtilstand"</string>
     <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Knapperne til afspilning er synlige"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Knapperne til afspilning er skjult. Tryk på D-pad for at se dem"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Knapperne til afspilning er skjult. Tryk på D-pad\'en for at se dem"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Afslut"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsæt"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-gu/strings.xml b/v17/leanback/res/values-gu/strings.xml
index bc021cb..4285f52 100644
--- a/v17/leanback/res/values-gu/strings.xml
+++ b/v17/leanback/res/values-gu/strings.xml
@@ -48,10 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ઉપશીર્ષક સક્ષમ કરો"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"વિગતવાર ઉપશીર્ષકોને અક્ષમ કરો"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ચિત્ર મોડમાં ચિત્ર દાખલ કરો"</string>
-    <!-- no translation found for lb_playback_controls_shown (6382160135512023238) -->
-    <skip />
-    <!-- no translation found for lb_playback_controls_hidden (8940984081242033574) -->
-    <skip />
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"મીડિયા નિયંત્રણો બતાવેલા છે"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"મીડિયા નિયંત્રણો છુપાયેલા છે, તે બતાવવા માટે d-પૅડ દબાવો"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"સમાપ્ત કરો"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ચાલુ રાખો"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-iw/strings.xml b/v17/leanback/res/values-iw/strings.xml
index 4d6d7f4..be2740b 100644
--- a/v17/leanback/res/values-iw/strings.xml
+++ b/v17/leanback/res/values-iw/strings.xml
@@ -48,10 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"הפעל כתוביות"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"השבת כתוביות"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"הזן את התמונה במצב תמונה"</string>
-    <!-- no translation found for lb_playback_controls_shown (6382160135512023238) -->
-    <skip />
-    <!-- no translation found for lb_playback_controls_hidden (8940984081242033574) -->
-    <skip />
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"פקדי המדיה מוצגים"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"‏פקדי המדיה מוסתרים. הקש על ה-d-pad כדי להציג אותם"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"סיום"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"המשך"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-te/strings.xml b/v17/leanback/res/values-te/strings.xml
index e1b3ba2..f9cb803 100644
--- a/v17/leanback/res/values-te/strings.xml
+++ b/v17/leanback/res/values-te/strings.xml
@@ -48,10 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"సంవృత శీర్షికలను ప్రారంభించు"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"సంవృత శీర్షికలను నిలిపివేయి"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"చిత్రంలో చిత్రం మోడ్‌లోకి ప్రవేశించండి"</string>
-    <!-- no translation found for lb_playback_controls_shown (6382160135512023238) -->
-    <skip />
-    <!-- no translation found for lb_playback_controls_hidden (8940984081242033574) -->
-    <skip />
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"మీడియా నియంత్రణలు చూపబడ్డాయి"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"మీడియా నియంత్రణలు దాచబడ్డాయి, చూపించడానికి d-ప్యాడ్ నొక్కండి"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ముగించు"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"కొనసాగించు"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
diff --git a/v17/leanback/res/values-uz/strings.xml b/v17/leanback/res/values-uz/strings.xml
index c491358..5a4151f 100644
--- a/v17/leanback/res/values-uz/strings.xml
+++ b/v17/leanback/res/values-uz/strings.xml
@@ -48,8 +48,8 @@
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Taglavhalarni yoqish"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Taglavhalarni o‘chirib qo‘yish"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"Tasvir ichida tasvir rejimiga kirish"</string>
-    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Boshqaruv elementlari ko‘rsatilgan"</string>
-    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Boshqaruv elementlari yashirilgan, ko‘rsatish uchun D-pad tugmasini bosing"</string>
+    <string name="lb_playback_controls_shown" msgid="6382160135512023238">"Boshqaruv elementlari ochiq"</string>
+    <string name="lb_playback_controls_hidden" msgid="8940984081242033574">"Boshqaruv elementlari berkitilgan, ochish uchun D-pad tugmasini bosing"</string>
     <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tugatish"</string>
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davom etish"</string>
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
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 8ab731f..ff5ef2e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
@@ -26,6 +26,7 @@
 /**
  * @hide
  */
+@SuppressWarnings("FragmentNotInstantiable")
 class BaseFragment extends BrandedFragment {
 
     /**
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 7d08738..62ee0d4 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
@@ -29,6 +29,7 @@
 /**
  * @hide
  */
+@SuppressWarnings("FragmentNotInstantiable")
 class BaseSupportFragment extends BrandedSupportFragment {
 
     /**
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 ed20153..6672398 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -1468,6 +1468,7 @@
             getChildFragmentManager().beginTransaction()
                     .replace(R.id.scale_frame, new Fragment()).commit();
             gridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+                @SuppressWarnings("ReferenceEquality")
                 @Override
                 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                     if (newState == RecyclerView.SCROLL_STATE_IDLE) {
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 43e10b2..5d0cee8 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -1471,6 +1471,7 @@
             getChildFragmentManager().beginTransaction()
                     .replace(R.id.scale_frame, new Fragment()).commit();
             gridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+                @SuppressWarnings("ReferenceEquality")
                 @Override
                 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                     if (newState == RecyclerView.SCROLL_STATE_IDLE) {
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 564c3c7..aa2a51f 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
@@ -185,7 +185,7 @@
     // No need to save/restore the logo resource ID, because the logo animation will not appear when
     // the fragment is restored.
     private int mLogoResourceId;
-    boolean mEnterTransitionFinished;
+    boolean mLogoAnimationFinished;
     int mCurrentPageIndex;
 
     private AnimatorSet mAnimator;
@@ -193,7 +193,7 @@
     private final OnClickListener mOnClickListener = new OnClickListener() {
         @Override
         public void onClick(View view) {
-            if (!mEnterTransitionFinished) {
+            if (!mLogoAnimationFinished) {
                 // Do not change page until the enter transition finishes.
                 return;
             }
@@ -208,7 +208,7 @@
     private final OnKeyListener mOnKeyListener = new OnKeyListener() {
         @Override
         public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (!mEnterTransitionFinished) {
+            if (!mLogoAnimationFinished) {
                 // Ignore key event until the enter transition finishes.
                 return keyCode != KeyEvent.KEYCODE_BACK;
             }
@@ -241,13 +241,28 @@
         }
     };
 
-    void moveToPreviousPage() {
+    /**
+     * Navigates to the previous page.
+     */
+    protected void moveToPreviousPage() {
+        if (!mLogoAnimationFinished) {
+            // Ignore if the logo enter transition is in progress.
+            return;
+        }
         if (mCurrentPageIndex > 0) {
             --mCurrentPageIndex;
             onPageChangedInternal(mCurrentPageIndex + 1);
         }
     }
-    void moveToNextPage() {
+
+    /**
+     * Navigates to the next page.
+     */
+    protected void moveToNextPage() {
+        if (!mLogoAnimationFinished) {
+            // Ignore if the logo enter transition is in progress.
+            return;
+        }
         if (mCurrentPageIndex < getPageCount() - 1) {
             ++mCurrentPageIndex;
             onPageChangedInternal(mCurrentPageIndex - 1);
@@ -281,7 +296,7 @@
         }
         if (savedInstanceState == null) {
             mCurrentPageIndex = 0;
-            mEnterTransitionFinished = false;
+            mLogoAnimationFinished = false;
             mPageIndicator.onPageSelected(0, false);
             view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
                 @Override
@@ -294,7 +309,7 @@
                 }
             });
         } else {
-            mEnterTransitionFinished = true;
+            mLogoAnimationFinished = true;
             mCurrentPageIndex = savedInstanceState.getInt(KEY_CURRENT_PAGE_INDEX);
             initializeViews(view);
         }
@@ -463,10 +478,19 @@
         // Header views.
         mTitleView.setText(getPageTitle(mCurrentPageIndex));
         mDescriptionView.setText(getPageDescription(mCurrentPageIndex));
+        onLogoAnimationFinished();
+    }
+
+    /**
+     * Called immediately after fragment views become visible. This method gives subclasses a chance
+     * to initialize themselves. If a logo animation is specified, calling this method is delayed
+     * until after the logo animation is complete.
+     */
+    protected void onLogoAnimationFinished() {
     }
 
     void startEnterAnimation() {
-        mEnterTransitionFinished = true;
+        mLogoAnimationFinished = true;
         initializeViews(getView());
         List<Animator> animators = new ArrayList<>();
         final Context context = FragmentUtil.getContext(this);
@@ -525,6 +549,15 @@
     }
 
     /**
+     * Returns whether the logo enter transition is finished.
+     *
+     * @return {@code true} if the logo enter transition is finished, {@code false} otherwise
+     */
+    protected final boolean isLogoAnimationFinished() {
+        return mLogoAnimationFinished;
+    }
+
+    /**
      * Returns the page count.
      *
      * @return The page count.
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 5df8f41..59a0f5f 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
@@ -188,7 +188,7 @@
     // No need to save/restore the logo resource ID, because the logo animation will not appear when
     // the fragment is restored.
     private int mLogoResourceId;
-    boolean mEnterTransitionFinished;
+    boolean mLogoAnimationFinished;
     int mCurrentPageIndex;
 
     private AnimatorSet mAnimator;
@@ -196,7 +196,7 @@
     private final OnClickListener mOnClickListener = new OnClickListener() {
         @Override
         public void onClick(View view) {
-            if (!mEnterTransitionFinished) {
+            if (!mLogoAnimationFinished) {
                 // Do not change page until the enter transition finishes.
                 return;
             }
@@ -211,7 +211,7 @@
     private final OnKeyListener mOnKeyListener = new OnKeyListener() {
         @Override
         public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (!mEnterTransitionFinished) {
+            if (!mLogoAnimationFinished) {
                 // Ignore key event until the enter transition finishes.
                 return keyCode != KeyEvent.KEYCODE_BACK;
             }
@@ -244,13 +244,28 @@
         }
     };
 
-    void moveToPreviousPage() {
+    /**
+     * Navigates to the previous page.
+     */
+    protected void moveToPreviousPage() {
+        if (!mLogoAnimationFinished) {
+            // Ignore if the logo enter transition is in progress.
+            return;
+        }
         if (mCurrentPageIndex > 0) {
             --mCurrentPageIndex;
             onPageChangedInternal(mCurrentPageIndex + 1);
         }
     }
-    void moveToNextPage() {
+
+    /**
+     * Navigates to the next page.
+     */
+    protected void moveToNextPage() {
+        if (!mLogoAnimationFinished) {
+            // Ignore if the logo enter transition is in progress.
+            return;
+        }
         if (mCurrentPageIndex < getPageCount() - 1) {
             ++mCurrentPageIndex;
             onPageChangedInternal(mCurrentPageIndex - 1);
@@ -284,7 +299,7 @@
         }
         if (savedInstanceState == null) {
             mCurrentPageIndex = 0;
-            mEnterTransitionFinished = false;
+            mLogoAnimationFinished = false;
             mPageIndicator.onPageSelected(0, false);
             view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
                 @Override
@@ -297,7 +312,7 @@
                 }
             });
         } else {
-            mEnterTransitionFinished = true;
+            mLogoAnimationFinished = true;
             mCurrentPageIndex = savedInstanceState.getInt(KEY_CURRENT_PAGE_INDEX);
             initializeViews(view);
         }
@@ -466,10 +481,19 @@
         // Header views.
         mTitleView.setText(getPageTitle(mCurrentPageIndex));
         mDescriptionView.setText(getPageDescription(mCurrentPageIndex));
+        onLogoAnimationFinished();
+    }
+
+    /**
+     * Called immediately after fragment views become visible. This method gives subclasses a chance
+     * to initialize themselves. If a logo animation is specified, calling this method is delayed
+     * until after the logo animation is complete.
+     */
+    protected void onLogoAnimationFinished() {
     }
 
     void startEnterAnimation() {
-        mEnterTransitionFinished = true;
+        mLogoAnimationFinished = true;
         initializeViews(getView());
         List<Animator> animators = new ArrayList<>();
         final Context context = getContext();
@@ -528,6 +552,15 @@
     }
 
     /**
+     * Returns whether the logo enter transition is finished.
+     *
+     * @return {@code true} if the logo enter transition is finished, {@code false} otherwise
+     */
+    protected final boolean isLogoAnimationFinished() {
+        return mLogoAnimationFinished;
+    }
+
+    /**
      * Returns the page count.
      *
      * @return The page count.
diff --git a/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java b/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java
index dd0127c..204f922 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java
@@ -382,17 +382,12 @@
      * @see MediaPlayer#setDataSource(String)
      */
     public boolean setMediaSource(Uri uri) {
-        if (mMediaSourceUri != null && mMediaSourceUri.equals(uri)) {
+        if (mMediaSourceUri != null ? mMediaSourceUri.equals(uri) : uri == null) {
             return false;
         }
-        if (mMediaSourceUri != null || mMediaSourcePath != null) {
-            mMediaSourceUri = uri;
-            mMediaSourcePath = null;
-            prepareMediaForPlaying();
-        } else {
-            mMediaSourceUri = uri;
-            prepareMediaForPlaying();
-        }
+        mMediaSourceUri = uri;
+        mMediaSourcePath = null;
+        prepareMediaForPlaying();
         return true;
     }
 
@@ -404,17 +399,12 @@
      * @see MediaPlayer#setDataSource(String)
      */
     public boolean setMediaSource(String path) {
-        if (mMediaSourcePath != null && mMediaSourcePath.equals(mMediaSourcePath)) {
+        if (mMediaSourcePath != null ? mMediaSourcePath.equals(path) : path == null) {
             return false;
         }
-        if (mMediaSourceUri != null || mMediaSourcePath != null) {
-            mMediaSourceUri = null;
-            mMediaSourcePath = path;
-            prepareMediaForPlaying();
-        } else {
-            mMediaSourcePath = path;
-            prepareMediaForPlaying();
-        }
+        mMediaSourceUri = null;
+        mMediaSourcePath = path;
+        prepareMediaForPlaying();
         return true;
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/util/StateMachine.java b/v17/leanback/src/android/support/v17/leanback/util/StateMachine.java
index a00bbc5..b9d2f2d 100644
--- a/v17/leanback/src/android/support/v17/leanback/util/StateMachine.java
+++ b/v17/leanback/src/android/support/v17/leanback/util/StateMachine.java
@@ -109,11 +109,6 @@
         public final int getStatus() {
             return mStatus;
         }
-
-        @Override
-        public final boolean equals(Object other) {
-            return this == other;
-        }
     }
 
     private boolean mSorted = true;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
index c607d64..196fa93 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
@@ -372,7 +372,7 @@
          * @param position The index of the child view to display.
          */
         public void setSelectedMediaItemNumberView(int position) {
-            if (position >= 0 & position < mMediaItemNumberViewFlipper.getChildCount()) {
+            if (position >= 0 && position < mMediaItemNumberViewFlipper.getChildCount()) {
                 mMediaItemNumberViewFlipper.setDisplayedChild(position);
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java b/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java
index 1064c45..1ced4d4 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java
@@ -55,7 +55,7 @@
         }
     }
 
-    class OneLineActionPresenter extends Presenter {
+    static class OneLineActionPresenter extends Presenter {
         @Override
         public ViewHolder onCreateViewHolder(ViewGroup parent) {
             View v = LayoutInflater.from(parent.getContext())
@@ -77,7 +77,7 @@
         }
     }
 
-    class TwoLineActionPresenter extends Presenter {
+    static class TwoLineActionPresenter extends Presenter {
         @Override
         public ViewHolder onCreateViewHolder(ViewGroup parent) {
             View v = LayoutInflater.from(parent.getContext())
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
index 0bd03f1..50f0da3 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
@@ -182,8 +182,8 @@
 
     void setSharedElementEnterTransition(Activity activity, String sharedElementName,
             long timeoutMs) {
-        if (activity == null && !TextUtils.isEmpty(sharedElementName)
-                || activity != null && TextUtils.isEmpty(sharedElementName)) {
+        if ((activity == null && !TextUtils.isEmpty(sharedElementName))
+                || (activity != null && TextUtils.isEmpty(sharedElementName))) {
             throw new IllegalArgumentException();
         }
         if (activity == mActivityToRunTransition
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
index 728d31f..988a9fc 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
@@ -251,7 +251,7 @@
             }
         }
 
-        class HeaderFocusAnimator extends FocusAnimator {
+        static class HeaderFocusAnimator extends FocusAnimator {
 
             ItemBridgeAdapter.ViewHolder mViewHolder;
             HeaderFocusAnimator(View view, float scale, int duration) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
index 570a7f2..c2d57b6 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
@@ -74,8 +74,8 @@
 
     public void setSharedElementEnterTransition(Activity activity, String sharedElementName,
             long timeoutMs) {
-        if (activity == null && !TextUtils.isEmpty(sharedElementName)
-                || activity != null && TextUtils.isEmpty(sharedElementName)) {
+        if ((activity == null && !TextUtils.isEmpty(sharedElementName))
+                || (activity != null && TextUtils.isEmpty(sharedElementName))) {
             throw new IllegalArgumentException();
         }
         if (activity == mActivityToRunTransition
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 9098743..c2780be 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -1655,14 +1655,14 @@
                 ? Gravity.getAbsoluteGravity(mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK,
                 View.LAYOUT_DIRECTION_RTL)
                 : mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-        if (mOrientation == HORIZONTAL && verticalGravity == Gravity.TOP
-                || mOrientation == VERTICAL && horizontalGravity == Gravity.LEFT) {
+        if ((mOrientation == HORIZONTAL && verticalGravity == Gravity.TOP)
+                || (mOrientation == VERTICAL && horizontalGravity == Gravity.LEFT)) {
             // do nothing
-        } else if (mOrientation == HORIZONTAL && verticalGravity == Gravity.BOTTOM
-                || mOrientation == VERTICAL && horizontalGravity == Gravity.RIGHT) {
+        } else if ((mOrientation == HORIZONTAL && verticalGravity == Gravity.BOTTOM)
+                || (mOrientation == VERTICAL && horizontalGravity == Gravity.RIGHT)) {
             startSecondary += getRowSizeSecondary(rowIndex) - sizeSecondary;
-        } else if (mOrientation == HORIZONTAL && verticalGravity == Gravity.CENTER_VERTICAL
-                || mOrientation == VERTICAL && horizontalGravity == Gravity.CENTER_HORIZONTAL) {
+        } else if ((mOrientation == HORIZONTAL && verticalGravity == Gravity.CENTER_VERTICAL)
+                || (mOrientation == VERTICAL && horizontalGravity == Gravity.CENTER_HORIZONTAL)) {
             startSecondary += (getRowSizeSecondary(rowIndex) - sizeSecondary) / 2;
         }
         int left, top, right, bottom;
@@ -2418,7 +2418,7 @@
 
     public void setSelection(int position, int subposition, boolean smooth,
             int primaryScrollExtra) {
-        if (mFocusPosition != position && position != NO_POSITION
+        if ((mFocusPosition != position && position != NO_POSITION)
                 || subposition != mSubFocusPosition || primaryScrollExtra != mPrimaryScrollExtra) {
             scrollToSelection(position, subposition, smooth, primaryScrollExtra);
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
index 62ff2d7..632c287 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
@@ -13,15 +13,14 @@
  */
 package android.support.v17.leanback.widget;
 
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.StringRes;
 import android.support.v17.leanback.R;
 import android.support.v4.content.ContextCompat;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
 import android.text.InputType;
 
 import java.util.List;
@@ -201,10 +200,10 @@
                 mTitle = mContext.getString(R.string.lb_guidedaction_continue_title);
             } else if (id == ACTION_ID_YES) {
                 mId = ACTION_ID_YES;
-                mTitle = mContext.getString(android.R.string.yes);
+                mTitle = mContext.getString(android.R.string.ok);
             } else if (id == ACTION_ID_NO) {
                 mId = ACTION_ID_NO;
-                mTitle = mContext.getString(android.R.string.no);
+                mTitle = mContext.getString(android.R.string.cancel);
             }
             return (B) this;
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java
index 3230848..b0e681a 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java
@@ -55,8 +55,9 @@
                 }
             }
             if (facet.mOffsetPercent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
-                alignPos += ((view == itemView ? p.getOpticalWidth(view) : view.getWidth())
-                        * facet.mOffsetPercent) / 100f;
+                alignPos += Math.round(
+                        ((view == itemView ? p.getOpticalWidth(view) : view.getWidth())
+                        * facet.mOffsetPercent) / 100f);
             }
             if (itemView != view) {
                 sRect.left = alignPos;
@@ -74,8 +75,9 @@
                 }
             }
             if (facet.mOffsetPercent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
-                alignPos += ((view == itemView ? p.getOpticalHeight(view) : view.getHeight())
-                        * facet.mOffsetPercent) / 100f;
+                alignPos += Math.round(
+                        ((view == itemView ? p.getOpticalHeight(view) : view.getHeight())
+                        * facet.mOffsetPercent) / 100f);
             }
             if (itemView != view) {
                 sRect.top = alignPos;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
index 3556057..4bc00c6 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
@@ -213,6 +213,7 @@
         return space;
     }
 
+    @SuppressWarnings("ReferenceEquality")
     protected static float getFontDescent(TextView textView, Paint fontMeasurePaint) {
         if (fontMeasurePaint.getTextSize() != textView.getTextSize()) {
             fontMeasurePaint.setTextSize(textView.getTextSize());
diff --git a/v4/AndroidManifest.xml b/v4/AndroidManifest.xml
index 642a916..470f5c2 100644
--- a/v4/AndroidManifest.xml
+++ b/v4/AndroidManifest.xml
@@ -17,6 +17,7 @@
           xmlns:tools="http://schemas.android.com/tools"
           package="android.support.v4">
     <uses-sdk android:minSdkVersion="14" tools:overrideLibrary="android.support.v4"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v7/appcompat/AndroidManifest.xml b/v7/appcompat/AndroidManifest.xml
index c1ff659..7de91ff 100644
--- a/v7/appcompat/AndroidManifest.xml
+++ b/v7/appcompat/AndroidManifest.xml
@@ -18,6 +18,7 @@
           package="android.support.v7.appcompat">
     <uses-sdk android:minSdkVersion="14"
               tools:overrideLibrary="android.support.graphics.drawable.animated"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application/>
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBar.java b/v7/appcompat/src/android/support/v7/app/ActionBar.java
index 320cf7b..c619596 100644
--- a/v7/appcompat/src/android/support/v7/app/ActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/ActionBar.java
@@ -1069,6 +1069,12 @@
 
     /** @hide */
     @RestrictTo(LIBRARY_GROUP)
+    public boolean closeOptionsMenu() {
+        return false;
+    }
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
     public boolean invalidateOptionsMenu() {
         return false;
     }
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
index 6c0f125..57e4570 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
@@ -538,6 +538,14 @@
                 return true;
             }
         }
+        // Let support action bars open menus in response to the menu key prioritized over
+        // the window handling it
+        final int keyCode = event.getKeyCode();
+        final ActionBar actionBar = getSupportActionBar();
+        if (keyCode == KeyEvent.KEYCODE_MENU
+                && actionBar != null && actionBar.onMenuKeyEvent(event)) {
+            return true;
+        }
         return super.dispatchKeyEvent(event);
     }
 
@@ -576,4 +584,22 @@
         }
         return super.onKeyDown(keyCode, event);
     }
+
+    @Override
+    public void openOptionsMenu() {
+        ActionBar actionBar = getSupportActionBar();
+        if (getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)
+                && (actionBar == null || !actionBar.openOptionsMenu())) {
+            super.openOptionsMenu();
+        }
+    }
+
+    @Override
+    public void closeOptionsMenu() {
+        ActionBar actionBar = getSupportActionBar();
+        if (getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)
+                && (actionBar == null || !actionBar.closeOptionsMenu())) {
+            super.closeOptionsMenu();
+        }
+    }
 }
diff --git a/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
index 40b5c2b..9ac70af 100644
--- a/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
@@ -428,6 +428,11 @@
     }
 
     @Override
+    public boolean closeOptionsMenu() {
+        return mDecorToolbar.hideOverflowMenu();
+    }
+
+    @Override
     public boolean invalidateOptionsMenu() {
         mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
         ViewCompat.postOnAnimation(mDecorToolbar.getViewGroup(), mMenuInvalidator);
diff --git a/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java b/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java
index b0e7719..ad34238 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java
@@ -436,9 +436,11 @@
 
         popupWindow.show();
 
+        final ListView listView = popupWindow.getListView();
+        listView.setOnKeyListener(this);
+
         // If this is the root menu, show the title if requested.
         if (parentInfo == null && mShowTitle && menu.getHeaderTitle() != null) {
-            final ListView listView = popupWindow.getListView();
             final FrameLayout titleItemView = (FrameLayout) inflater.inflate(
                     R.layout.abc_popup_menu_header_item_layout, listView, false);
             final TextView titleView = (TextView) titleItemView.findViewById(android.R.id.title);
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java b/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
index cdaecc0..08d66c4 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
@@ -16,8 +16,66 @@
 
 package android.support.v7.app;
 
+import android.support.test.filters.SmallTest;
+import android.support.v7.widget.Toolbar;
+import android.view.KeyEvent;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
 public class KeyEventsTestCaseWithToolbar extends BaseKeyEventsTestCase<ToolbarAppCompatActivity> {
     public KeyEventsTestCaseWithToolbar() {
         super(ToolbarAppCompatActivity.class);
     }
+
+    @Test
+    @SmallTest
+    @Override
+    public void testMenuKeyEventReachesActivity() throws InterruptedException {
+        // With Toolbar, MENU key gets sent-to (and consumed by) Toolbar rather than Activity
+    }
+
+    @Test
+    @SmallTest
+    public void testMenuKeyOpensToolbarMenu() {
+        // Base test only checks that *a* menu is opened, we check here that the toolbar's menu
+        // specifically is opened.
+        Toolbar toolbar = mActivityTestRule.getActivity().getToolbar();
+        assertFalse(toolbar.isOverflowMenuShowing());
+
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+        getInstrumentation().waitForIdleSync();
+        assertTrue(toolbar.isOverflowMenuShowing());
+
+        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+        getInstrumentation().waitForIdleSync();
+        assertFalse(toolbar.isOverflowMenuShowing());
+    }
+
+    @Test
+    @SmallTest
+    public void testOpenMenuOpensToolbarMenu() throws Throwable {
+        Toolbar toolbar = mActivityTestRule.getActivity().getToolbar();
+        assertFalse(toolbar.isOverflowMenuShowing());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivityTestRule.getActivity().openOptionsMenu();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertTrue(toolbar.isOverflowMenuShowing());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivityTestRule.getActivity().closeOptionsMenu();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertFalse(toolbar.isOverflowMenuShowing());
+    }
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java b/v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java
index 9042363..3213f40 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java
@@ -34,4 +34,8 @@
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
         setSupportActionBar(mToolbar);
     }
+
+    public Toolbar getToolbar() {
+        return mToolbar;
+    }
 }
diff --git a/v7/cardview/AndroidManifest.xml b/v7/cardview/AndroidManifest.xml
index b83c815..8fcf55a 100644
--- a/v7/cardview/AndroidManifest.xml
+++ b/v7/cardview/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.cardview">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v7/gridlayout/AndroidManifest.xml b/v7/gridlayout/AndroidManifest.xml
index 6f12842..b6cb783 100644
--- a/v7/gridlayout/AndroidManifest.xml
+++ b/v7/gridlayout/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.gridlayout">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v7/mediarouter/AndroidManifest.xml b/v7/mediarouter/AndroidManifest.xml
index 5466168..c4577f9 100644
--- a/v7/mediarouter/AndroidManifest.xml
+++ b/v7/mediarouter/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.mediarouter">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v7/palette/AndroidManifest.xml b/v7/palette/AndroidManifest.xml
index 78735ba..8e5ffaa 100644
--- a/v7/palette/AndroidManifest.xml
+++ b/v7/palette/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.palette">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v7/preference/AndroidManifest.xml b/v7/preference/AndroidManifest.xml
index 6923656..772b410 100644
--- a/v7/preference/AndroidManifest.xml
+++ b/v7/preference/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.support.v7.preference">
     <uses-sdk android:minSdkVersion="14" />
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
-    <application />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/v7/recyclerview/AndroidManifest.xml b/v7/recyclerview/AndroidManifest.xml
index 5eef157..5b03882 100644
--- a/v7/recyclerview/AndroidManifest.xml
+++ b/v7/recyclerview/AndroidManifest.xml
@@ -16,5 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.v7.recyclerview">
     <uses-sdk android:minSdkVersion="14"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>
diff --git a/wearable/AndroidManifest.xml b/wearable/AndroidManifest.xml
index 77ac1b6..e4b1897 100644
--- a/wearable/AndroidManifest.xml
+++ b/wearable/AndroidManifest.xml
@@ -16,5 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.wearable">
     <uses-sdk android:minSdkVersion="22"/>
-    <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    <application>
+        <meta-data android:name="android.support.VERSION" android:value="${support-version}" />
+    </application>
 </manifest>